PRIVATE int parseSubOption(char* line, char **option, char **param) { const char *subopt_delim = "=>"; uint32_t i = 0; *option = NULL; *param = NULL; assert(line && *line); while(line[i] != '\0') { if(line[i] == subopt_delim[0] && line[i+1] == subopt_delim[1]) { *option = am_strndup(line, i-1); *param = trim(line + i + strlen(subopt_delim)); break; } i++; } return (*option && *param) ? SUCCESS : FAILURE; }
PRIVATE suboption_t* parseSubOption(char* line) { const char *subopt_delim = "=>"; uint32_t i = 0; suboption_t* option_item = NULL; char *option = NULL; char *param = NULL; assert(line && *line); while(line[i] != '\0') { if(line[i] == subopt_delim[0] && line[i+1] == subopt_delim[1]) { if(i >1) { option = am_strndup(line, i-1); param = trim(line + i + strlen(subopt_delim)); } else { dbg_printf(P_ERROR, "Error: Suboption '%s' is malformed!", line); } break; } i++; } if(option && param) { option_item = (suboption_t*)am_malloc(sizeof(suboption_t)); option_item->option = option; option_item->value = param; } if(!option_item) { dbg_printf(P_ERROR, "Error parsing suboption from input string '%s')", line); am_free(option); am_free(param); } return option_item; }
/* http://stackoverflow.com/questions/122616/how-do-i-trim-leading-trailing-whitespace-in-a-standard-way */ PRIVATE char* trim(const char *str) { const char *end; if(!str || !*str) { return NULL; } // Trim leading space while(isspace(*str)) { str++; } if(*str == 0) // All spaces? { return NULL; } /* skip single or double quote */ if (*str == '"' || *str == '\'') { str++; } // Trim trailing space end = str + strlen(str) - 1; while(end > str && isspace(*end)) { end--; } /* skip single or double quote */ if (*end == '"' || *end == '\'') { end--; } end++; // Return copy of trimmed string return am_strndup(str, end - str); }
PRIVATE size_t parse_Transmission_response(void *ptr, size_t size, size_t nmemb, void *data) { size_t line_len = size * nmemb; const char *line = ptr; WebData *mem = data; const char *session_key = "X-Transmission-Session-Id: "; const size_t key_len = strlen( session_key ); char *tmp = NULL; int content_length = 0; if( (line_len >= key_len) && !memcmp(line, session_key, key_len) ) { const char * begin = line + key_len; const char * end = begin; while( !isspace( *end ) ) { ++end; } am_free( gSessionID ); gSessionID = NULL; gSessionID = am_strndup( begin, end-begin ); /* parse header for Content-Length to allocate correct size for data->response->data */ } else if(line_len >= 15 && !memcmp(line, "Content-Length:", 15)) { tmp = getRegExMatch("Content-Length:\\s(\\d+)", line, 1); if(tmp != NULL) { dbg_printf(P_INFO2, "Content-Length: %s", tmp); content_length = atoi(tmp); if(content_length > 0) { mem->content_length = content_length; mem->response->buffer_size = content_length + 1; mem->response->data = am_realloc(mem->response->data, mem->response->buffer_size); } am_free(tmp); } } return line_len; }
/** \brief Upload data to a specified URL. * * \param url Path to where data shall be uploaded * \param auth (Optional) authentication information in the form of "user:password" * \param data Data that shall be uploaded * \param data_size size of the data * \return Web server response */ PUBLIC HTTPResponse* sendHTTPData(const char *url, const char* auth, const void *data, uint32_t data_size) { CURL *curl_handle = NULL; CURLcode res; long rc, tries = 2, len; WebData* response_data = NULL; HTTPResponse* resp = NULL; char sessionKey[MAXLEN]; struct curl_slist * headers = NULL; if( !url || !data ) { return NULL; } response_data = WebData_new(url); do { --tries; WebData_clear(response_data); if( curl_handle == NULL) { if(gbGlobalInitDone == FALSE) { curl_global_init(CURL_GLOBAL_ALL); gbGlobalInitDone = TRUE; } if( ( curl_handle = am_curl_init(auth, TRUE) ) ) { curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, response_data); curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, response_data); //Transmission-specific options for HTTP POST if(strstr(response_data->url, "transmission") != NULL) { curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, parse_Transmission_response ); headers = curl_slist_append(headers, "Content-Type: application/json"); if( gSessionID ) { if((len = snprintf(sessionKey, MAXLEN, "X-Transmission-Session-Id: %s", gSessionID)) > 0) { sessionKey[len] = '\0'; } headers = curl_slist_append(headers, sessionKey); } curl_easy_setopt( curl_handle, CURLOPT_HTTPHEADER, headers ); } curl_easy_setopt(curl_handle, CURLOPT_URL, response_data->url); } else { dbg_printf(P_ERROR, "am_curl_init() failed"); break; } } curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, data); curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, data_size); if( ( res = curl_easy_perform(curl_handle) ) ) { dbg_printf(P_ERROR, "Upload to '%s' failed: %s", url, curl_easy_strerror(res)); break; } else { curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &rc); dbg_printf(P_INFO2, "response code: %ld", rc); if(rc == 409) { if(gSessionID) { dbg_printf(P_DBG, "Error code 409, session ID: %s", gSessionID); } else { dbg_printf(P_ERROR, "Error code 409, no session ID"); } closeCURLSession( curl_handle ); curl_slist_free_all( headers ); headers = NULL; curl_handle = NULL; } else { resp = HTTPResponse_new(); curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &resp->responseCode); //copy data if present if(response_data->response->data) { resp->size = response_data->response->buffer_pos; resp->data = am_strndup(response_data->response->data, resp->size); } //copy filename if present if(response_data->content_filename) { resp->content_filename = am_strdup(response_data->content_filename); } break; } } } while(tries > 0); /* cleanup */ closeCURLSession(curl_handle); if(headers) { curl_slist_free_all(headers); } WebData_free(response_data); return resp; }
PUBLIC HTTPResponse* getHTTPData(const char *url, const char *cookies, CURL ** curl_session) { CURLcode res; CURL *curl_handle = NULL; CURL *session = *curl_session; char *escaped_url = NULL; WebData *data = NULL; HTTPResponse *resp = NULL; long responseCode = -1; if(!url) { return NULL; } data = WebData_new(url); if(!data) { return NULL; } dbg_printf(P_INFO2, "[getHTTPData] url=%s, curl_session=%p", url, (void*)session); if(session == NULL) { if(gbGlobalInitDone == FALSE) { curl_global_init(CURL_GLOBAL_ALL); gbGlobalInitDone = TRUE; } session = am_curl_init(NULL, FALSE); *curl_session = session; } curl_handle = session; if(curl_handle) { escaped_url = url_encode_whitespace(url); assert(escaped_url); curl_easy_setopt(curl_handle, CURLOPT_URL, escaped_url); curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, data); curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, data); if(cookies && *cookies) { /* if there's an explicit cookie string, use it */ curl_easy_setopt(curl_handle, CURLOPT_COOKIE, cookies); } else { /* otherwise, enable cookie-handling since there might be cookies defined within the URL */ curl_easy_setopt(curl_handle, CURLOPT_COOKIEFILE, ""); } res = curl_easy_perform(curl_handle); /* curl_easy_cleanup(curl_handle); */ curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &responseCode); dbg_printf(P_INFO2, "[getHTTPData] response code: %d", responseCode); if(res != 0) { dbg_printf(P_ERROR, "[getHTTPData] '%s': %s (retval: %d)", url, curl_easy_strerror(res), res); } else { /* Only the very first connection attempt (where curl_session == NULL) should store the session, ** and only the last one should close the session. */ resp = HTTPResponse_new(); resp->responseCode = responseCode; //copy data if present if(data->response->data) { resp->size = data->response->buffer_pos; resp->data = am_strndup(data->response->data, resp->size); } //copy filename if present if(data->content_filename) { resp->content_filename = am_strdup(data->content_filename); } } am_free(escaped_url); } else { dbg_printf(P_ERROR, "curl_handle is uninitialized!"); resp = NULL; } WebData_free(data); return resp; }