/** * Callback function that put a "Hello World!" string in the response */ int callback_get (const struct _u_request * request, struct _u_response * response, void * user_data) { struct _u_request * req = ulfius_duplicate_request(request); struct _u_response * res = malloc(sizeof(struct _u_response)); ulfius_init_response(res); int len; free(req->http_url); u_map_remove_from_key(req->map_header, "Host"); len = snprintf(NULL, 0, "%s%s", PROXY_DEST, request->http_url); req->http_url = malloc((len+1)*sizeof(char)); snprintf(req->http_url, (len+1), "%s%s", PROXY_DEST, request->http_url); ulfius_send_http_request(req, res); ulfius_copy_response(response, res); ulfius_clean_response_full(res); ulfius_clean_request_full(req); return U_OK; }
/** * create a new request based on the source elements * returned value must be free'd */ struct _u_request * ulfius_duplicate_request(const struct _u_request * request) { struct _u_request * new_request = NULL; if (request != NULL) { new_request = malloc(sizeof(struct _u_request)); if (new_request == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for new_request"); return NULL; } if (ulfius_init_request(new_request) == U_OK) { new_request->http_verb = nstrdup(request->http_verb); new_request->http_url = nstrdup(request->http_url); if (new_request->http_verb == NULL || new_request->http_url == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for ulfius_duplicate_request"); ulfius_clean_request_full(new_request); return NULL; } if (request->client_address != NULL) { new_request->client_address = malloc(sizeof(struct sockaddr)); if (new_request->client_address == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for new_request->client_address"); ulfius_clean_request_full(new_request); return NULL; } memcpy(new_request->client_address, request->client_address, sizeof(struct sockaddr)); } u_map_clean_full(new_request->map_url); u_map_clean_full(new_request->map_header); u_map_clean_full(new_request->map_cookie); u_map_clean_full(new_request->map_post_body); new_request->map_url = u_map_copy(request->map_url); new_request->map_header = u_map_copy(request->map_header); new_request->map_cookie = u_map_copy(request->map_cookie); new_request->map_post_body = u_map_copy(request->map_post_body); new_request->json_body = json_copy(request->json_body); new_request->json_has_error = request->json_has_error; if ((new_request->map_url == NULL && request->map_url != NULL) || (new_request->map_header == NULL && request->map_header != NULL) || (new_request->map_cookie == NULL && request->map_cookie != NULL) || (new_request->map_post_body == NULL && request->map_post_body != NULL) || (new_request->json_body == NULL && request->json_body != NULL)) { ulfius_clean_request_full(new_request); return NULL; } if (request->binary_body != NULL && request->binary_body_length > 0) { new_request->binary_body = malloc(request->binary_body_length); if (new_request->binary_body == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for new_request->binary_body"); ulfius_clean_request_full(new_request); return NULL; } memcpy(new_request->binary_body, request->binary_body, request->binary_body_length); } else { new_request->binary_body_length = 0; new_request->binary_body = NULL; } new_request->binary_body_length = request->binary_body_length; } else { free(new_request); new_request = NULL; } } return new_request; }
/** * ulfius_send_http_streaming_request * Send a HTTP request and store the result into a _u_response * Except for the body which will be available using write_body_function in the write_body_data * return U_OK on success */ int ulfius_send_http_streaming_request(const struct _u_request * request, struct _u_response * response, size_t (* write_body_function)(void * contents, size_t size, size_t nmemb, void * user_data), void * write_body_data) { CURLcode res; CURL * curl_handle = NULL; struct curl_slist * header_list = NULL; char * key_esc, * value_esc, * cookie, * header, * param, * fp = "?", * np = "&"; const char * value, ** keys; int i, has_params = 0, len; struct _u_request * copy_request = NULL; if (request != NULL) { // Duplicate the request and work on it copy_request = ulfius_duplicate_request(request); if (copy_request == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error ulfius_duplicate_request"); return U_ERROR_MEMORY; } curl_handle = curl_easy_init(); if (copy_request != NULL) { // Append header values if (copy_request->map_header == NULL) { copy_request->map_header = malloc(sizeof(struct _u_map)); if (copy_request->map_header == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for copy_request->map_header"); ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } if (u_map_init(copy_request->map_header) != U_OK) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } } // Set basic auth if defined if (copy_request->auth_basic_user != NULL && copy_request->auth_basic_password != NULL) { if (curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC) == CURLE_OK) { if (curl_easy_setopt(curl_handle, CURLOPT_USERNAME, copy_request->auth_basic_user) != CURLE_OK || curl_easy_setopt(curl_handle, CURLOPT_PASSWORD, copy_request->auth_basic_password) != CURLE_OK) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting HTTP Basic user name or password"); ulfius_clean_request_full(copy_request); curl_easy_cleanup(curl_handle); return U_ERROR_LIBCURL; } } else { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting HTTP Basic Auth option"); ulfius_clean_request_full(copy_request); curl_easy_cleanup(curl_handle); return U_ERROR_LIBCURL; } } has_params = (strchr(copy_request->http_url, '?') != NULL); if (copy_request->map_url != NULL && u_map_count(copy_request->map_url) > 0) { // Append url parameters keys = u_map_enum_keys(copy_request->map_url); // Append parameters from map_url for (i=0; keys != NULL && keys[i] != NULL; i++) { value = u_map_get(copy_request->map_url, keys[i]); key_esc = curl_easy_escape(curl_handle, keys[i], 0); value_esc = curl_easy_escape(curl_handle, value, 0); if (key_esc == NULL || value_esc == NULL) { curl_free(key_esc); curl_free(value_esc); ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } param = msprintf("%s=%s", key_esc, value_esc); if (param == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for param"); curl_free(key_esc); curl_free(value_esc); ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } if (has_params == 0) { copy_request->http_url = realloc(copy_request->http_url, strlen(copy_request->http_url) + strlen(param) + 2); if (copy_request->http_url == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for copy_request->http_url"); free(param); curl_free(key_esc); curl_free(value_esc); ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } strcat(copy_request->http_url, fp); strcat(copy_request->http_url, param); has_params = 1; } else { copy_request->http_url = realloc(copy_request->http_url, strlen(copy_request->http_url) + strlen(param) + 2); if (copy_request->http_url == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for copy_request->http_url"); free(param); curl_free(key_esc); curl_free(value_esc); ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } strcat(copy_request->http_url, np); strcat(copy_request->http_url, param); } free(param); curl_free(key_esc); curl_free(value_esc); } } if (copy_request->json_body != NULL) { // Append json body parameter free(copy_request->binary_body); copy_request->binary_body = json_dumps(copy_request->json_body, JSON_COMPACT); if (copy_request->binary_body == NULL) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } else { copy_request->binary_body_length = strlen(copy_request->binary_body); if (u_map_put(copy_request->map_header, ULFIUS_HTTP_HEADER_CONTENT, ULFIUS_HTTP_ENCODING_JSON) != U_OK) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } } } else if (u_map_count(copy_request->map_post_body) > 0) { // Append MHD_HTTP_POST_ENCODING_FORM_URLENCODED post parameters keys = u_map_enum_keys(copy_request->map_post_body); for (i=0; keys != NULL && keys[i] != NULL; i++) { // Build parameter value = u_map_get(copy_request->map_post_body, keys[i]); if (value == NULL) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } key_esc = curl_easy_escape(curl_handle, keys[i], 0); value_esc = curl_easy_escape(curl_handle, value, 0); if (key_esc == NULL || value_esc == NULL) { curl_free(key_esc); curl_free(value_esc); ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } param = msprintf("%s=%s", key_esc, value_esc); if (param == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for param"); curl_free(key_esc); curl_free(value_esc); ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } // Append parameter to body if (copy_request->binary_body_length == 0) { len = strlen(param) + sizeof(char); copy_request->binary_body = malloc(len); if (copy_request->binary_body == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for copy_request->binary_body"); free(param); curl_free(key_esc); curl_free(value_esc); ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } strcpy(copy_request->binary_body, ""); strcat(copy_request->binary_body, param); copy_request->binary_body_length = len; } else { len = (copy_request->binary_body_length + strlen(param) + sizeof(char)); copy_request->binary_body = realloc(copy_request->binary_body, len); if (copy_request->binary_body == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for copy_request->binary_body"); free(param); curl_free(key_esc); curl_free(value_esc); ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } memcpy(copy_request->binary_body + copy_request->binary_body_length, np, 1); memcpy(copy_request->binary_body + copy_request->binary_body_length + 1, param, strlen(param)); copy_request->binary_body_length = len; } free(param); curl_free(key_esc); curl_free(value_esc); } if (curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, copy_request->binary_body) != CURLE_OK) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting POST fields"); return U_ERROR_LIBCURL; } if (u_map_put(copy_request->map_header, ULFIUS_HTTP_HEADER_CONTENT, MHD_HTTP_POST_ENCODING_FORM_URLENCODED) != U_OK) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } } if (copy_request->map_header != NULL && u_map_count(copy_request->map_header) > 0) { // Append map headers keys = u_map_enum_keys(copy_request->map_header); for (i=0; keys != NULL && keys[i] != NULL; i++) { value = u_map_get(copy_request->map_header, keys[i]); if (value == NULL) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } header = msprintf("%s:%s", keys[i], value); if (header == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for header"); ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } header_list = curl_slist_append(header_list, header); if (header_list == NULL) { free(header); ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } free(header); } } if (copy_request->map_cookie != NULL && u_map_count(copy_request->map_cookie) > 0) { // Append cookies keys = u_map_enum_keys(copy_request->map_cookie); for (i=0; keys != NULL && keys[i] != NULL; i++) { value = u_map_get(copy_request->map_cookie, keys[i]); if (value == NULL) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } cookie = msprintf("%s=%s", keys[i], value); if (cookie == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for cookie"); ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } if (curl_easy_setopt(curl_handle, CURLOPT_COOKIE, cookie) != CURLE_OK) { free(cookie); ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); return U_ERROR_MEMORY; } free(cookie); } } // Request parameters if (curl_easy_setopt(curl_handle, CURLOPT_URL, copy_request->http_url) != CURLE_OK || curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, copy_request->http_verb) != CURLE_OK || curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, header_list) != CURLE_OK) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting libcurl options (1)"); return U_ERROR_LIBCURL; } // Set CURLOPT_WRITEFUNCTION if specified if (write_body_function != NULL && curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_body_function) != CURLE_OK) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting libcurl options (2)"); return U_ERROR_LIBCURL; } // Set CURLOPT_WRITEDATA if specified if (write_body_data != NULL && curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, write_body_data) != CURLE_OK) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting libcurl options (3)"); return U_ERROR_LIBCURL; } // Disable certificate validation if needed if (!copy_request->check_server_certificate) { if (curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0) != CURLE_OK || curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0) != CURLE_OK) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting libcurl options (4)"); return U_ERROR_LIBCURL; } } // Response parameters if (response != NULL) { if (response->map_header != NULL) { if (curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, write_header) != CURLE_OK || curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, response) != CURLE_OK) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting headers"); return U_ERROR_LIBCURL; } } } if (copy_request->binary_body != NULL) { if (curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, copy_request->binary_body) != CURLE_OK) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting POST fields"); return U_ERROR_LIBCURL; } if (copy_request->binary_body_length > 0) { if (curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, copy_request->binary_body_length) != CURLE_OK) { ulfius_clean_request_full(copy_request); curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting POST fields"); return U_ERROR_LIBCURL; } } } if (curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1) != CURLE_OK) { curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); ulfius_clean_request_full(copy_request); y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting libcurl CURLOPT_NOSIGNAL"); return U_ERROR_LIBCURL; } res = curl_easy_perform(curl_handle); if(res == CURLE_OK && response != NULL) { if (curl_easy_getinfo (curl_handle, CURLINFO_RESPONSE_CODE, &response->status) != CURLE_OK) { curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); ulfius_clean_request_full(copy_request); y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error executing http request, libcurl error: %d, error message %s", res, curl_easy_strerror(res)); return U_ERROR_LIBCURL; } } curl_slist_free_all(header_list); curl_easy_cleanup(curl_handle); ulfius_clean_request_full(copy_request); if (res == CURLE_OK) { return U_OK; } else { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error executing curl command: %s", curl_easy_strerror(res)); return U_ERROR_LIBCURL; } } } return U_ERROR_PARAMS; }