X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fgns%2Fgnunet-gns-proxy.c;h=cdc18e3f6b156ca8bfab88ffcf423f4ce292c10a;hb=bcbd694ad35e182e5a1486b545ea0706082ee94a;hp=8ebc4bfc65555f39c4199f385c26e8fa5014f20b;hpb=f8976258f12b4639d868c02053f88c2c1e8a6e50;p=oweals%2Fgnunet.git diff --git a/src/gns/gnunet-gns-proxy.c b/src/gns/gnunet-gns-proxy.c index 8ebc4bfc6..cdc18e3f6 100644 --- a/src/gns/gnunet-gns-proxy.c +++ b/src/gns/gnunet-gns-proxy.c @@ -34,6 +34,8 @@ #include #include +#define HAVE_MHD_NO_LISTEN_SOCKET MHD_VERSION >= 0x00091401 + #define GNUNET_GNS_PROXY_PORT 7777 #define MHD_MAX_CONNECTIONS 300 #define MAX_HTTP_URI_LENGTH 2048 @@ -189,9 +191,15 @@ struct ProxyCurlTask /* DLL for tasks */ struct ProxyCurlTask *next; + /* Already accepted */ + int accepted; + /* Handle to cURL */ CURL *curl; + /* is curl running? */ + int curl_running; + /* Optional header replacements for curl (LEHO) */ struct curl_slist *headers; @@ -252,6 +260,9 @@ struct ProxyCurlTask /* The hostname (Host header field) */ char host[256]; + /* The port */ + uint16_t port; + /* The LEgacy HOstname (can be empty) */ char leho[256]; @@ -284,10 +295,19 @@ struct ProxyCurlTask struct MHD_PostProcessor *post_handler; /* post data */ - struct ProxyPostData *post_data_head; - struct ProxyPostData *post_data_tail; + struct ProxyUploadData *upload_data_head; + struct ProxyUploadData *upload_data_tail; int post_done; + + /* the type of POST encoding */ + char* post_type; + + struct curl_httppost *httppost; + + struct curl_httppost *httppost_last; + + int is_httppost; }; @@ -342,13 +362,21 @@ struct ProxySetCookieHeader /** * Post data structure */ -struct ProxyPostData +struct ProxyUploadData { /* DLL */ - struct ProxyPostData *next; + struct ProxyUploadData *next; /* DLL */ - struct ProxyPostData *prev; + struct ProxyUploadData *prev; + + char *key; + + char *filename; + + char *content_type; + + size_t content_length; /* value */ char *value; @@ -404,13 +432,13 @@ static struct MhdHttpList *mhd_httpd_tail; static regex_t re_dotplus; /* The users local GNS zone hash */ -static struct GNUNET_CRYPTO_ShortHashCode local_gns_zone; +static struct GNUNET_CRYPTO_ShortHashCode *local_gns_zone; /* The users local private zone */ -static struct GNUNET_CRYPTO_ShortHashCode local_private_zone; +static struct GNUNET_CRYPTO_ShortHashCode *local_private_zone; /* The users local shorten zone */ -static struct GNUNET_CRYPTO_ShortHashCode local_shorten_zone; +static struct GNUNET_CRYPTO_ShortHashCode *local_shorten_zone; /* The CA for SSL certificate generation */ static struct ProxyCA proxy_ca; @@ -461,7 +489,7 @@ char i_to_hexchar (char i) } /** - * Escape giben 0-terminated string + * Escape given 0-terminated string * * @param to_esc string to escapse * @return allocated new escaped string (MUST free!) @@ -505,22 +533,85 @@ con_post_data_iter (void *cls, size_t size) { struct ProxyCurlTask* ctask = cls; - struct ProxyPostData* pdata; + struct ProxyUploadData* pdata; char* enc; + char* new_value; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got POST data: '%s : %s' at offset %llu size %lld\n", key, data, off, size); - /* FIXME ! if transfer enc == urlenc! */ + GNUNET_assert (NULL != ctask->post_type); + + if (0 == strcasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, + ctask->post_type)) + { + ctask->is_httppost = GNUNET_YES; + /* new part */ + if (0 == off) + { + pdata = GNUNET_malloc (sizeof (struct ProxyUploadData)); + pdata->key = strdup (key); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copied %lld\n"); + + if (NULL != filename) + { + pdata->filename = strdup (filename); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Filename %s\n", filename); + } + + if (NULL != content_type) + { + pdata->content_type = strdup (content_type); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Content-Type %s\n", content_type); + } + + pdata->value = GNUNET_malloc (size); + pdata->total_bytes = size; + memcpy (pdata->value, data, size); + GNUNET_CONTAINER_DLL_insert_tail (ctask->upload_data_head, + ctask->upload_data_tail, + pdata); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copied %lld bytes of POST Data\n", size); + return MHD_YES; + } + + pdata = ctask->upload_data_tail; + new_value = GNUNET_malloc (size + pdata->total_bytes); + memcpy (new_value, pdata->value, pdata->total_bytes); + memcpy (new_value+off, data, size); + GNUNET_free (pdata->value); + pdata->value = new_value; + pdata->total_bytes += size; + + return MHD_YES; + + } + + if (0 != strcasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, + ctask->post_type)) + { + return MHD_NO; + } + + ctask->is_httppost = GNUNET_NO; + + if (NULL != ctask->curl) + curl_easy_pause (ctask->curl, CURLPAUSE_CONT); if (0 == off) { /* a key */ - pdata = GNUNET_malloc (sizeof (struct ProxyPostData)); + pdata = GNUNET_malloc (sizeof (struct ProxyUploadData)); enc = escape_to_urlenc (key); pdata->value = GNUNET_malloc (strlen (enc) + 3); - if (NULL != ctask->post_data_head) + if (NULL != ctask->upload_data_head) { pdata->value[0] = '&'; memcpy (pdata->value+1, enc, strlen (enc)); @@ -536,13 +627,13 @@ con_post_data_iter (void *cls, "Escaped POST key: '%s'\n", pdata->value); - GNUNET_CONTAINER_DLL_insert_tail (ctask->post_data_head, - ctask->post_data_tail, + GNUNET_CONTAINER_DLL_insert_tail (ctask->upload_data_head, + ctask->upload_data_tail, pdata); } /* a value */ - pdata = GNUNET_malloc (sizeof (struct ProxyPostData)); + pdata = GNUNET_malloc (sizeof (struct ProxyUploadData)); enc = escape_to_urlenc (data); pdata->value = GNUNET_malloc (strlen (enc) + 1); memcpy (pdata->value, enc, strlen (enc)); @@ -554,28 +645,13 @@ con_post_data_iter (void *cls, "Escaped POST value: '%s'\n", pdata->value); - GNUNET_CONTAINER_DLL_insert_tail (ctask->post_data_head, - ctask->post_data_tail, + GNUNET_CONTAINER_DLL_insert_tail (ctask->upload_data_head, + ctask->upload_data_tail, pdata); return MHD_YES; } -static int -get_uri_val_iter (void *cls, - enum MHD_ValueKind kind, - const char *key, - const char *value) -{ - char* buf = cls; - - if (strlen (buf) + strlen (value) + 3 > MAX_HTTP_URI_LENGTH) - return MHD_NO; - sprintf (buf+strlen (buf), "?%s=%s", key, value); - - return MHD_YES; -} - /** * Read HTTP request header field 'Host' * @@ -593,12 +669,28 @@ con_val_iter (void *cls, { struct ProxyCurlTask *ctask = cls; char* buf = ctask->host; + char* port; char* cstr; const char* hdr_val; + unsigned int uport; if (0 == strcmp ("Host", key)) { - strcpy (buf, value); + port = strstr (value, ":"); + if (NULL != port) + { + strncpy (buf, value, port-value); + port++; + if ((1 != sscanf (port, "%u", &uport)) || + (uport > UINT16_MAX) || + (0 == uport)) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse port!\n"); + else + ctask->port = (uint16_t) uport; + } + else + strcpy (buf, value); return MHD_YES; } @@ -607,6 +699,22 @@ con_val_iter (void *cls, else hdr_val = value; + if (0 == strcasecmp (MHD_HTTP_HEADER_CONTENT_TYPE, + key)) + { + if (0 == strncasecmp (value, + MHD_HTTP_POST_ENCODING_FORM_URLENCODED, + strlen (MHD_HTTP_POST_ENCODING_FORM_URLENCODED))) + ctask->post_type = MHD_HTTP_POST_ENCODING_FORM_URLENCODED; + else if (0 == strncasecmp (value, + MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, + strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))) + ctask->post_type = MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA; + else + ctask->post_type = NULL; + + } + cstr = GNUNET_malloc (strlen (key) + strlen (hdr_val) + 3); GNUNET_snprintf (cstr, strlen (key) + strlen (hdr_val) + 3, "%s: %s", key, hdr_val); @@ -665,6 +773,7 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) char* hdr_val; int delta_cdomain; size_t offset = 0; + char cors_hdr[strlen (ctask->leho) + strlen ("https://")]; if (NULL == ctask->response) { @@ -676,8 +785,30 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) &mhd_content_cb, ctask, NULL); + + /* if we have a leho add a CORS header */ + if (0 != strcmp ("", ctask->leho)) + { + /* We could also allow ssl and http here */ + if (ctask->mhd->is_ssl) + sprintf (cors_hdr, "https://%s", ctask->leho); + else + sprintf (cors_hdr, "http://%s", ctask->leho); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: Adding CORS header field %s\n", + cors_hdr); + + if (GNUNET_NO == MHD_add_response_header (ctask->response, + "Access-Control-Allow-Origin", + cors_hdr)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "MHD: Error adding CORS header field %s\n", + cors_hdr); + } + } ctask->ready_to_queue = GNUNET_YES; - } if (html_mime_len <= bytes) @@ -895,8 +1026,9 @@ mhd_content_free (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ProxyCurlTask *ctask = cls; - GNUNET_assert (NULL == ctask->pp_match_head); + struct ProxyUploadData *pdata; + GNUNET_assert (NULL == ctask->pp_match_head); if (NULL != ctask->headers) curl_slist_free_all (ctask->headers); @@ -906,7 +1038,20 @@ mhd_content_free (void *cls, if (NULL != ctask->response) MHD_destroy_response (ctask->response); + if (NULL != ctask->post_handler) + MHD_destroy_post_processor (ctask->post_handler); + for (pdata = ctask->upload_data_head; NULL != pdata; pdata = ctask->upload_data_head) + { + GNUNET_CONTAINER_DLL_remove (ctask->upload_data_head, + ctask->upload_data_tail, + pdata); + GNUNET_free_non_null (pdata->filename); + GNUNET_free_non_null (pdata->content_type); + GNUNET_free_non_null (pdata->key); + GNUNET_free_non_null (pdata->value); + GNUNET_free (pdata); + } GNUNET_free (ctask); } @@ -927,7 +1072,7 @@ mhd_content_cb (void *cls, size_t max) { struct ProxyCurlTask *ctask = cls; - struct ProxyREMatch *re_match = ctask->pp_match_head; + struct ProxyREMatch *re_match; ssize_t copied = 0; long long int bytes_to_copy = ctask->buffer_write_ptr - ctask->buffer_read_ptr; @@ -968,7 +1113,7 @@ mhd_content_cb (void *cls, return 0; copied = 0; - for (; NULL != re_match; re_match = ctask->pp_match_head) + for (re_match = ctask->pp_match_head; NULL != re_match; re_match = ctask->pp_match_head) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MHD: Processing PP %s\n", @@ -1071,6 +1216,7 @@ mhd_content_cb (void *cls, return copied; } + /** * Shorten result callback * @@ -1174,9 +1320,9 @@ postprocess_buffer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) re_match->shorten_task = GNUNET_GNS_shorten_zone (gns_handle, re_match->hostname, - &local_private_zone, - &local_shorten_zone, - &local_gns_zone, + local_private_zone, + local_shorten_zone, + local_gns_zone, &process_shorten, re_match); //FIXME cancel appropriately @@ -1213,6 +1359,9 @@ curl_download_cb (void *ptr, size_t size, size_t nmemb, void* ctx) "CURL: Got %d. %d free in buffer\n", total, buf_space); + if (BUF_WAIT_FOR_CURL != ctask->buf_status) + return CURL_WRITEFUNC_PAUSE; + if (total > (buf_space - CURL_BUF_PADDING)) { if (ctask->buf_status == BUF_WAIT_FOR_CURL) @@ -1241,41 +1390,89 @@ curl_download_cb (void *ptr, size_t size, size_t nmemb, void* ctx) return total; } + /** - * cURL callback for post data + * cURL callback for put data */ static size_t -read_callback (void *buf, size_t size, size_t nmemb, void *cls) +put_read_callback (void *buf, size_t size, size_t nmemb, void *cls) { struct ProxyCurlTask *ctask = cls; - struct ProxyPostData *pdata = ctask->post_data_head; + struct ProxyUploadData *pdata = ctask->upload_data_head; size_t len = size * nmemb; size_t to_copy; char* pos; - char tmp[2048]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "CURL: read callback\n"); + "CURL: put read callback\n"); if (NULL == pdata) - return 0; + return CURL_READFUNC_PAUSE; //fin if (NULL == pdata->value) { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CURL: Terminating PUT\n"); + + GNUNET_CONTAINER_DLL_remove (ctask->upload_data_head, + ctask->upload_data_tail, + pdata); + GNUNET_free (pdata); return 0; - if (len < 2) - return 0; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CURL: read callback value %s\n", pdata->value); + + to_copy = pdata->bytes_left; + if (to_copy > len) + to_copy = len; + + pos = pdata->value + (pdata->total_bytes - pdata->bytes_left); + memcpy (buf, pos, to_copy); + pdata->bytes_left -= to_copy; + if (pdata->bytes_left <= 0) + { + GNUNET_free (pdata->value); + GNUNET_CONTAINER_DLL_remove (ctask->upload_data_head, + ctask->upload_data_tail, + pdata); + GNUNET_free (pdata); + } + return to_copy; +} + +/** + * cURL callback for post data + */ +static size_t +post_read_callback (void *buf, size_t size, size_t nmemb, void *cls) +{ + struct ProxyCurlTask *ctask = cls; + struct ProxyUploadData *pdata = ctask->upload_data_head; + size_t len = size * nmemb; + size_t to_copy; + char* pos; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CURL: read callback\n"); + + if (NULL == pdata) + return CURL_READFUNC_PAUSE; + + //fin + if (NULL == pdata->value) + { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CURL: Terminating POST data\n"); - memcpy (buf, "\n\r", 2); - GNUNET_CONTAINER_DLL_remove (ctask->post_data_head, - ctask->post_data_tail, + GNUNET_CONTAINER_DLL_remove (ctask->upload_data_head, + ctask->upload_data_tail, pdata); GNUNET_free (pdata); - return 2; + return 0; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -1287,16 +1484,12 @@ read_callback (void *buf, size_t size, size_t nmemb, void *cls) pos = pdata->value + (pdata->total_bytes - pdata->bytes_left); memcpy (buf, pos, to_copy); - memcpy (tmp, pos, to_copy); - tmp[to_copy] = 'c'; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "CURL: Wrote %s\n", tmp); pdata->bytes_left -= to_copy; if (pdata->bytes_left <= 0) { GNUNET_free (pdata->value); - GNUNET_CONTAINER_DLL_remove (ctask->post_data_head, - ctask->post_data_tail, + GNUNET_CONTAINER_DLL_remove (ctask->upload_data_head, + ctask->upload_data_tail, pdata); GNUNET_free (pdata); } @@ -1372,13 +1565,12 @@ curl_download_prepare () else if (NULL != ctasks_head) { /* as specified in curl docs */ - curl_download_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + curl_download_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, &curl_task_download, curl_multi); } GNUNET_NETWORK_fdset_destroy (gws); GNUNET_NETWORK_fdset_destroy (grs); - } @@ -1409,8 +1601,8 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Shutdown requested while trying to download\n"); - //TODO cleanup - return; + //TODO cleanup + return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ready to dl\n"); @@ -1425,8 +1617,7 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running curl tasks: %d\n", running); - ctask = ctasks_head; - for (; ctask != NULL; ctask = ctask->next) + for (ctask = ctasks_head; NULL != ctask; ctask = ctask->next) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CTask: %s\n", ctask->url); @@ -1441,7 +1632,7 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) do { - ctask = ctasks_head; + msg = curl_multi_info_read (curl_multi, &msgnum); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Messages left: %d\n", msgnum); @@ -1457,7 +1648,7 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Download curl failed"); - for (; ctask != NULL; ctask = ctask->next) + for (ctask = ctasks_head; NULL != ctask; ctask = ctask->next) { if (NULL == ctask->curl) continue; @@ -1491,15 +1682,12 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CURL: download completed.\n"); - for (; ctask != NULL; ctask = ctask->next) + for (ctask = ctasks_head; NULL != ctask; ctask = ctask->next) { if (NULL == ctask->curl) continue; - if (memcmp (msg->easy_handle, ctask->curl, sizeof (CURL)) != 0) - continue; - - if (ctask->buf_status != BUF_WAIT_FOR_CURL) + if (0 != memcmp (msg->easy_handle, ctask->curl, sizeof (CURL))) continue; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -1540,7 +1728,7 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) } } while (msgnum > 0); - for (ctask=clean_head; ctask != NULL; ctask = ctask->next) + for (ctask=clean_head; NULL != ctask; ctask = ctask->next) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CURL: Removing task %s.\n", ctask->url); @@ -1550,7 +1738,7 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) } num_ctasks=0; - for (ctask=ctasks_head; ctask != NULL; ctask = ctask->next) + for (ctask=ctasks_head; NULL != ctask; ctask = ctask->next) { num_ctasks++; } @@ -1574,6 +1762,7 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) curl_download_prepare(); } + /** * Process LEHO lookup * @@ -1615,7 +1804,7 @@ process_leho_lookup (void *cls, if (0 != strcmp (ctask->leho, "")) { - sprintf (hosthdr, "%s%s", "Host: ", ctask->leho); + sprintf (hosthdr, "%s%s:%d", "Host: ", ctask->leho, ctask->port); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New HTTP header value: %s\n", hosthdr); ctask->headers = curl_slist_append (ctask->headers, hosthdr); @@ -1643,7 +1832,7 @@ process_leho_lookup (void *cls, "Curl resolve: %s\n", resolvename); ctask->resolver = curl_slist_append ( ctask->resolver, resolvename); curl_easy_setopt (ctask->curl, CURLOPT_RESOLVE, ctask->resolver); - sprintf (curlurl, "https://%s%s", ctask->leho, ctask->url); + sprintf (curlurl, "https://%s:%d%s", ctask->leho, ctask->port, ctask->url); curl_easy_setopt (ctask->curl, CURLOPT_URL, curlurl); } else @@ -1700,7 +1889,7 @@ process_get_authority (void *cls, GNUNET_GNS_lookup_zone (gns_handle, ctask->host, - &local_gns_zone, + local_gns_zone, GNUNET_GNS_RECORD_LEHO, GNUNET_YES, //Only cached for performance shorten_zonekey, @@ -1708,6 +1897,16 @@ process_get_authority (void *cls, ctask); } +static void* +mhd_log_callback (void* cls, const char* url) +{ + struct ProxyCurlTask *ctask; + + ctask = GNUNET_malloc (sizeof (struct ProxyCurlTask)); + strcpy (ctask->url, url); + ctask->accepted = GNUNET_NO; + return ctask; +} /** * Main MHD callback for handling requests. @@ -1748,14 +1947,18 @@ create_response (void *cls, char curlurl[MAX_HTTP_URI_LENGTH]; // buffer overflow! int ret = MHD_YES; + int i; - struct ProxyCurlTask *ctask; - struct ProxyPostData *fin_post; + struct ProxyCurlTask *ctask = *con_cls; + struct ProxyUploadData *fin_post; + struct curl_forms forms[5]; + struct ProxyUploadData *upload_data_iter; //FIXME handle if ((0 != strcasecmp (meth, MHD_HTTP_METHOD_GET)) && (0 != strcasecmp (meth, MHD_HTTP_METHOD_PUT)) && - (0 != strcasecmp (meth, MHD_HTTP_METHOD_POST))) + (0 != strcasecmp (meth, MHD_HTTP_METHOD_POST)) && + (0 != strcasecmp (meth, MHD_HTTP_METHOD_HEAD))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MHD: %s NOT IMPLEMENTED!\n", meth); @@ -1763,16 +1966,14 @@ create_response (void *cls, } - if (NULL == *con_cls) + if (GNUNET_NO == ctask->accepted) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got %s request for %s\n", meth, url); - ctask = GNUNET_malloc (sizeof (struct ProxyCurlTask)); ctask->mhd = hd; - *con_cls = ctask; - ctask->curl = curl_easy_init(); + ctask->curl_running = GNUNET_NO; if (NULL == ctask->curl) { ctask->response = MHD_create_response_from_buffer (strlen (page), @@ -1785,7 +1986,38 @@ create_response (void *cls, GNUNET_free (ctask); return ret; } - + + if (ctask->mhd->is_ssl) + ctask->port = HTTPS_PORT; + else + ctask->port = HTTP_PORT; + + MHD_get_connection_values (con, + MHD_HEADER_KIND, + &con_val_iter, ctask); + + curl_easy_setopt (ctask->curl, CURLOPT_HEADERFUNCTION, &curl_check_hdr); + curl_easy_setopt (ctask->curl, CURLOPT_HEADERDATA, ctask); + curl_easy_setopt (ctask->curl, CURLOPT_WRITEFUNCTION, &curl_download_cb); + curl_easy_setopt (ctask->curl, CURLOPT_WRITEDATA, ctask); + curl_easy_setopt (ctask->curl, CURLOPT_FOLLOWLOCATION, 0); + curl_easy_setopt (ctask->curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + + if (GNUNET_NO == ctask->mhd->is_ssl) + { + sprintf (curlurl, "http://%s:%d%s", ctask->host, ctask->port, ctask->url); + curl_easy_setopt (ctask->curl, CURLOPT_URL, curlurl); + } + + + curl_easy_setopt (ctask->curl, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (ctask->curl, CURLOPT_CONNECTTIMEOUT, 600L); + curl_easy_setopt (ctask->curl, CURLOPT_TIMEOUT, 600L); + + /* Add GNS header */ + ctask->headers = curl_slist_append (ctask->headers, + "GNS: YES"); + ctask->accepted = GNUNET_YES; ctask->download_in_progress = GNUNET_YES; ctask->buf_status = BUF_WAIT_FOR_CURL; ctask->connection = con; @@ -1793,82 +2025,44 @@ create_response (void *cls, ctask->buffer_read_ptr = ctask->buffer; ctask->buffer_write_ptr = ctask->buffer; ctask->pp_task = GNUNET_SCHEDULER_NO_TASK; - - MHD_get_connection_values (con, - MHD_HEADER_KIND, - &con_val_iter, ctask); + if (0 == strcasecmp (meth, MHD_HTTP_METHOD_PUT)) { - if (0 == *upload_data_size) - { - curl_easy_cleanup (ctask->curl); - GNUNET_free (ctask); - return MHD_NO; - } - ctask->put_read_offset = 0; - ctask->put_read_size = *upload_data_size; - curl_easy_setopt (ctask->curl, CURLOPT_UPLOAD, 1); - curl_easy_setopt (ctask->curl, CURLOPT_READDATA, upload_data); - //curl_easy_setopt (ctask->curl, CURLOPT_READFUNCTION, &curl_read_cb); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Setting up PUT\n"); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Got PUT data: %s\n", upload_data); - curl_easy_cleanup (ctask->curl); - GNUNET_free (ctask); - return MHD_NO; + curl_easy_setopt (ctask->curl, CURLOPT_UPLOAD, 1); + curl_easy_setopt (ctask->curl, CURLOPT_READDATA, ctask); + curl_easy_setopt (ctask->curl, CURLOPT_READFUNCTION, &put_read_callback); + ctask->headers = curl_slist_append (ctask->headers, + "Transfer-Encoding: chunked"); } if (0 == strcasecmp (meth, MHD_HTTP_METHOD_POST)) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, + //FIXME handle multipart + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting up POST processor\n"); ctask->post_handler = MHD_create_post_processor (con, POSTBUFFERSIZE, &con_post_data_iter, ctask); - curl_easy_setopt (ctask->curl, CURLOPT_POST, 1); - curl_easy_setopt (ctask->curl, CURLOPT_READFUNCTION, - &read_callback); - curl_easy_setopt (ctask->curl, CURLOPT_READDATA, ctask); ctask->headers = curl_slist_append (ctask->headers, - "Transfer-Encoding: chunked"); - /*curl_easy_setopt (ctask->curl, CURLOPT_POST, 1); - curl_easy_setopt (ctask->curl, CURLOPT_POSTFIELDSIZE, *upload_data_size); - curl_easy_setopt (ctask->curl, CURLOPT_COPYPOSTFIELDS, upload_data); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Got POST data: %s\n", upload_data); - curl_easy_cleanup (ctask->curl); - GNUNET_free (ctask); - return MHD_NO;*/ + "Transfer-Encoding: chunked"); + return MHD_YES; } - curl_easy_setopt (ctask->curl, CURLOPT_HEADERFUNCTION, &curl_check_hdr); - curl_easy_setopt (ctask->curl, CURLOPT_HEADERDATA, ctask); - curl_easy_setopt (ctask->curl, CURLOPT_WRITEFUNCTION, &curl_download_cb); - curl_easy_setopt (ctask->curl, CURLOPT_WRITEDATA, ctask); - curl_easy_setopt (ctask->curl, CURLOPT_FOLLOWLOCATION, 0); - curl_easy_setopt (ctask->curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); - - if (GNUNET_NO == ctask->mhd->is_ssl) + if (0 == strcasecmp (meth, MHD_HTTP_METHOD_HEAD)) { - sprintf (curlurl, "http://%s%s", ctask->host, url); - MHD_get_connection_values (con, - MHD_GET_ARGUMENT_KIND, - &get_uri_val_iter, curlurl); - curl_easy_setopt (ctask->curl, CURLOPT_URL, curlurl); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Setting NOBODY\n"); + curl_easy_setopt (ctask->curl, CURLOPT_NOBODY, 1); } - strcpy (ctask->url, url); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "MHD: Adding new curl task for %s%s\n", ctask->host, url); - MHD_get_connection_values (con, - MHD_GET_ARGUMENT_KIND, - &get_uri_val_iter, ctask->url); - - curl_easy_setopt (ctask->curl, CURLOPT_FAILONERROR, 1); - curl_easy_setopt (ctask->curl, CURLOPT_CONNECTTIMEOUT, 600L); - curl_easy_setopt (ctask->curl, CURLOPT_TIMEOUT, 600L); + "MHD: Adding new curl task for %s\n", ctask->host); GNUNET_GNS_get_authority (gns_handle, ctask->host, @@ -1876,6 +2070,7 @@ create_response (void *cls, ctask); ctask->ready_to_queue = GNUNET_NO; ctask->fin = GNUNET_NO; + ctask->curl_running = GNUNET_YES; return MHD_YES; } @@ -1884,18 +2079,95 @@ create_response (void *cls, { if (0 != *upload_data_size) { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Invoking POST processor\n"); MHD_post_process (ctask->post_handler, upload_data, *upload_data_size); *upload_data_size = 0; + if ((GNUNET_NO == ctask->is_httppost) && + (GNUNET_NO == ctask->curl_running)) + { + curl_easy_setopt (ctask->curl, CURLOPT_POST, 1); + curl_easy_setopt (ctask->curl, CURLOPT_READFUNCTION, + &post_read_callback); + curl_easy_setopt (ctask->curl, CURLOPT_READDATA, ctask); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: Adding new curl task for %s\n", ctask->host); + + GNUNET_GNS_get_authority (gns_handle, + ctask->host, + &process_get_authority, + ctask); + ctask->ready_to_queue = GNUNET_NO; + ctask->fin = GNUNET_NO; + ctask->curl_running = GNUNET_YES; + } return MHD_YES; } else if (GNUNET_NO == ctask->post_done) { - fin_post = GNUNET_malloc (sizeof (struct ProxyPostData)); - GNUNET_CONTAINER_DLL_insert_tail (ctask->post_data_head, - ctask->post_data_tail, + if (GNUNET_YES == ctask->is_httppost) + { + for (upload_data_iter = ctask->upload_data_head; + NULL != upload_data_iter; + upload_data_iter = upload_data_iter->next) + { + i = 0; + if (NULL != upload_data_iter->filename) + { + forms[i].option = CURLFORM_FILENAME; + forms[i].value = upload_data_iter->filename; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding filename %s\n", + forms[i].value); + i++; + } + if (NULL != upload_data_iter->content_type) + { + forms[i].option = CURLFORM_CONTENTTYPE; + forms[i].value = upload_data_iter->content_type; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding content type %s\n", + forms[i].value); + i++; + } + forms[i].option = CURLFORM_PTRCONTENTS; + forms[i].value = upload_data_iter->value; + forms[i+1].option = CURLFORM_END; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding formdata for %s (len=%lld)\n", + upload_data_iter->key, + upload_data_iter->total_bytes); + + curl_formadd(&ctask->httppost, &ctask->httppost_last, + CURLFORM_COPYNAME, upload_data_iter->key, + CURLFORM_CONTENTSLENGTH, upload_data_iter->total_bytes, + CURLFORM_ARRAY, forms, + CURLFORM_END); + } + curl_easy_setopt (ctask->curl, CURLOPT_HTTPPOST, + ctask->httppost); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: Adding new curl task for %s\n", ctask->host); + + GNUNET_GNS_get_authority (gns_handle, + ctask->host, + &process_get_authority, + ctask); + ctask->ready_to_queue = GNUNET_YES; + ctask->fin = GNUNET_NO; + ctask->curl_running = GNUNET_YES; + ctask->post_done = GNUNET_YES; + return MHD_YES; + } + + fin_post = GNUNET_malloc (sizeof (struct ProxyUploadData)); + GNUNET_CONTAINER_DLL_insert_tail (ctask->upload_data_head, + ctask->upload_data_tail, fin_post); ctask->post_done = GNUNET_YES; return MHD_YES; @@ -2451,18 +2723,28 @@ add_handle_to_ssl_mhd (struct GNUNET_NETWORK_Handle *h, const char* domain) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No previous SSL instance found... starting new one for %s\n", domain); - - hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL, 4444, - &accept_cb, NULL, - &create_response, hd, + hd->daemon = MHD_start_daemon (MHD_USE_DEBUG + | MHD_USE_SSL +#if HAVE_MHD_NO_LISTEN_SOCKET + | MHD_USE_NO_LISTEN_SOCKET, + 0, +#else + , 4444, //Dummy +#endif + &accept_cb, NULL, + &create_response, hd, +#if !HAVE_MHD_NO_LISTEN_SOCKET MHD_OPTION_LISTEN_SOCKET, GNUNET_NETWORK_get_fd (mhd_unix_socket), - MHD_OPTION_CONNECTION_LIMIT, MHD_MAX_CONNECTIONS, - MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, - MHD_OPTION_NOTIFY_COMPLETED, - NULL, NULL, - MHD_OPTION_HTTPS_MEM_KEY, pgc->key, - MHD_OPTION_HTTPS_MEM_CERT, pgc->cert, - MHD_OPTION_END); +#endif + MHD_OPTION_CONNECTION_LIMIT, + MHD_MAX_CONNECTIONS, + MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, + MHD_OPTION_NOTIFY_COMPLETED, NULL, NULL, + MHD_OPTION_HTTPS_MEM_KEY, pgc->key, + MHD_OPTION_HTTPS_MEM_CERT, pgc->cert, + MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, + NULL, + MHD_OPTION_END); GNUNET_assert (hd->daemon != NULL); hd->httpd_task = GNUNET_SCHEDULER_NO_TASK; @@ -2825,11 +3107,19 @@ do_shutdown (void *cls, struct NetworkHandleList *tmp_nh; struct ProxyCurlTask *ctask; struct ProxyCurlTask *ctask_tmp; + struct ProxyUploadData *pdata; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n"); gnutls_global_deinit (); + + if (NULL != local_gns_zone) + GNUNET_free (local_gns_zone); + if (NULL != local_private_zone) + GNUNET_free (local_private_zone); + if (NULL != local_shorten_zone) + GNUNET_free (local_shorten_zone); if (GNUNET_SCHEDULER_NO_TASK != curl_download_task) { @@ -2896,6 +3186,20 @@ do_shutdown (void *cls, if (NULL != ctask->response) MHD_destroy_response (ctask->response); + pdata = ctask->upload_data_head; + + //FIXME free pdata here + for (; pdata != NULL; pdata = ctask->upload_data_head) + { + GNUNET_CONTAINER_DLL_remove (ctask->upload_data_head, + ctask->upload_data_tail, + pdata); + GNUNET_free_non_null (pdata->filename); + GNUNET_free_non_null (pdata->content_type); + GNUNET_free_non_null (pdata->key); + GNUNET_free_non_null (pdata->value); + GNUNET_free (pdata); + } GNUNET_free (ctask); } @@ -2962,69 +3266,74 @@ load_local_zone_key (const struct GNUNET_CONFIGURATION_Handle *cfg) key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); + local_gns_zone = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_ShortHashCode)); GNUNET_CRYPTO_short_hash(&pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &local_gns_zone); - zone = &local_gns_zone; + local_gns_zone); + zone = local_gns_zone; GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zone: %s!\n", &zonename); GNUNET_CRYPTO_rsa_key_free(key); GNUNET_free(keyfile); - + keyfile = NULL; + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", "PRIVATE_ZONEKEY", &keyfile)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to load private zone key config value!\n"); - return GNUNET_NO; } - if (GNUNET_NO == GNUNET_DISK_file_test (keyfile)) + if ((NULL != keyfile) && (GNUNET_NO == GNUNET_DISK_file_test (keyfile))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to load private zone key %s!\n", keyfile); GNUNET_free(keyfile); - return GNUNET_NO; } - - key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); - GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); - GNUNET_CRYPTO_short_hash(&pkey, - sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &local_private_zone); - GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Using private zone: %s!\n", &zonename); - GNUNET_CRYPTO_rsa_key_free(key); - GNUNET_free(keyfile); + else + { + key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); + local_private_zone = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_ShortHashCode)); + GNUNET_CRYPTO_short_hash(&pkey, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + local_private_zone); + GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Using private zone: %s!\n", &zonename); + GNUNET_CRYPTO_rsa_key_free(key); + GNUNET_free(keyfile); + } + keyfile = NULL; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", "SHORTEN_ZONEKEY", &keyfile)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to load shorten zone key config value!\n"); - return GNUNET_NO; } - if (GNUNET_NO == GNUNET_DISK_file_test (keyfile)) + if ((NULL != keyfile) && (GNUNET_NO == GNUNET_DISK_file_test (keyfile))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to load shorten zone key %s!\n", keyfile); GNUNET_free(keyfile); - return GNUNET_NO; } - - key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); - GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); - GNUNET_CRYPTO_short_hash(&pkey, - sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &local_shorten_zone); - GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Using shorten zone: %s!\n", &zonename); - GNUNET_CRYPTO_rsa_key_free(key); - GNUNET_free(keyfile); + else + { + key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); + local_shorten_zone = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_ShortHashCode)); + GNUNET_CRYPTO_short_hash(&pkey, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + local_shorten_zone); + GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Using shorten zone: %s!\n", &zonename); + GNUNET_CRYPTO_rsa_key_free(key); + GNUNET_free(keyfile); + } return GNUNET_YES; } @@ -3043,11 +3352,13 @@ run (void *cls, char *const *args, const char *cfgfile, { struct sockaddr_in sa; struct MhdHttpList *hd; - struct sockaddr_un mhd_unix_sock_addr; - size_t len; - char* proxy_sockfile; char* cafile_cfg = NULL; char* cafile; +#if !HAVE_MHD_NO_LISTEN_SOCKET + size_t len; + char* proxy_sockfile; + struct sockaddr_un mhd_unix_sock_addr; +#endif curl_multi = curl_multi_init (); @@ -3075,6 +3386,8 @@ run (void *cls, char *const *args, const char *cfgfile, } cafile = cafile_cfg; } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Using %s as CA\n", cafile); gnutls_global_init (); gnutls_x509_crt_init (&proxy_ca.cert); @@ -3162,7 +3475,7 @@ run (void *cls, char *const *args, const char *cfgfile, mhd_httpd_head = NULL; mhd_httpd_tail = NULL; total_mhd_connections = 0; - +#ifndef HAVE_MHD_NO_LISTEN_SOCKET if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns-proxy", "PROXY_UNIXPATH", &proxy_sockfile)) @@ -3171,7 +3484,7 @@ run (void *cls, char *const *args, const char *cfgfile, "Specify PROXY_UNIXPATH in gns-proxy config section!\n"); return; } - + mhd_unix_socket = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); @@ -3213,18 +3526,28 @@ run (void *cls, char *const *args, const char *cfgfile, "Unable to listen on unix domain socket!\n"); return; } +#endif hd = GNUNET_malloc (sizeof (struct MhdHttpList)); hd->is_ssl = GNUNET_NO; strcpy (hd->domain, ""); - httpd = MHD_start_daemon (MHD_USE_DEBUG, 4444, //Dummy port + httpd = MHD_start_daemon (MHD_USE_DEBUG +#if HAVE_MHD_NO_LISTEN_SOCKET + | MHD_USE_NO_LISTEN_SOCKET, + 0, +#else + , 4444, //Dummy port +#endif &accept_cb, NULL, &create_response, hd, +#if !HAVE_MHD_NO_LISTEN_SOCKET MHD_OPTION_LISTEN_SOCKET, GNUNET_NETWORK_get_fd (mhd_unix_socket), +#endif MHD_OPTION_CONNECTION_LIMIT, MHD_MAX_CONNECTIONS, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, MHD_OPTION_NOTIFY_COMPLETED, NULL, NULL, + MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, NULL, MHD_OPTION_END); GNUNET_assert (httpd != NULL);