diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-09-18 13:12:00 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-09-18 13:12:00 +0000 |
commit | 1cf0cbbd5fa8f7cccff037f08f229d78f521eb54 (patch) | |
tree | 4fae0ed724515520bbc1d0c785111e05bec79259 | |
parent | 2b74f7a94df138bd6f732334033574bdc1727250 (diff) |
more work on GNS proxy, adding back to standard build
-rw-r--r-- | src/gns/Makefile.am | 3 | ||||
-rw-r--r-- | src/gns/gnunet-gns-proxy.c | 2127 |
2 files changed, 616 insertions, 1514 deletions
diff --git a/src/gns/Makefile.am b/src/gns/Makefile.am index 3c7c3ea685..3536536e03 100644 --- a/src/gns/Makefile.am +++ b/src/gns/Makefile.am @@ -47,13 +47,10 @@ lib_LTLIBRARIES = \ if HAVE_MHD if HAVE_GNUTLS if HAVE_LIBCURL -# does not compile right now... -if HAVE_EXPERIMENTAL DO_PROXY=gnunet-gns-proxy endif endif endif -endif libexec_PROGRAMS = \ gnunet-service-gns \ diff --git a/src/gns/gnunet-gns-proxy.c b/src/gns/gnunet-gns-proxy.c index e9bda690dd..cb74c8bec3 100644 --- a/src/gns/gnunet-gns-proxy.c +++ b/src/gns/gnunet-gns-proxy.c @@ -25,11 +25,11 @@ * with legacy browsers * * TODO: - * - make DNS lookup asynchronous - * - simplify POST/PUT processing + * - actually check SSL certificates * - double-check queueing logic - * - figure out what to do with the 'authority' issue - * - document better + * - handle cookie rewriting + * - handle location rewriting + * - improve IPv6 support */ #include "platform.h" #include <microhttpd.h> @@ -57,10 +57,10 @@ #define MAX_HTTP_URI_LENGTH 2048 /** - * Some buffer size. @deprecated + * Size of the buffer for the data upload / download. Must be + * enough for curl, thus CURL_MAX_WRITE_SIZE is needed here (16k). */ -#define POSTBUFFERSIZE 4096 - +#define IO_BUFFERSIZE CURL_MAX_WRITE_SIZE /** * Size of the read/write buffers for Socks. Uses @@ -286,140 +286,6 @@ struct Socks5ServerResponseMessage }; -/* ***************** Datastructures for Socks handling **************** */ - - -/** - * The socks phases. - */ -enum SocksPhase -{ - /** - * We're waiting to get the client hello. - */ - SOCKS5_INIT, - - /** - * We're waiting to get the initial request. - */ - SOCKS5_REQUEST, - - /** - * We are currently resolving the destination. - */ - SOCKS5_RESOLVING, - - /** - * We're in transfer mode. - */ - SOCKS5_DATA_TRANSFER, - - /** - * Finish writing the write buffer, then clean up. - */ - SOCKS5_WRITE_THEN_CLEANUP, - - /** - * Socket has been passed to MHD, do not close it anymore. - */ - SOCKS5_SOCKET_WITH_MHD -}; - - - -/** - * A structure for socks requests - */ -struct Socks5Request -{ - - /** - * DLL. - */ - struct Socks5Request *next; - - /** - * DLL. - */ - struct Socks5Request *prev; - - /** - * The client socket - */ - struct GNUNET_NETWORK_Handle *sock; - - /** - * Handle to GNS lookup, during #SOCKS5_RESOLVING phase. - */ - struct GNUNET_GNS_LookupRequest *gns_lookup; - - /** - * Client socket read task - */ - GNUNET_SCHEDULER_TaskIdentifier rtask; - - /** - * Client socket write task - */ - GNUNET_SCHEDULER_TaskIdentifier wtask; - - /** - * Timeout task - */ - GNUNET_SCHEDULER_TaskIdentifier timeout_task; - - /** - * Read buffer - */ - char rbuf[SOCKS_BUFFERSIZE]; - - /** - * Write buffer - */ - char wbuf[SOCKS_BUFFERSIZE]; - - /** - * the domain name to server (only important for SSL) - */ - char *domain; - - /** - * DNS Legacy Host Name as given by GNS, NULL if not given. - */ - char *leho; - - /** - * The URL to fetch - */ - char *url; - - /** - * Number of bytes already in read buffer - */ - size_t rbuf_len; - - /** - * Number of bytes already in write buffer - */ - size_t wbuf_len; - - /** - * Once known, what's the target address for the connection? - */ - struct sockaddr_storage destination_address; - - /** - * The socks state - */ - enum SocksPhase state; - - /** - * Desired destination port. - */ - uint16_t port; - -}; - /* *********************** Datastructures for HTTP handling ****************** */ @@ -501,252 +367,197 @@ struct MhdHttpList }; -/* ***************** possibly deprecated data structures ****************** */ - - -/** - * State machine for the IO buffer. - */ -enum BufferStatus - { - BUF_WAIT_FOR_CURL, - BUF_WAIT_FOR_MHD - }; +/* ***************** Datastructures for Socks handling **************** */ /** - * A structure for MHD<->cURL streams + * The socks phases. */ -struct ProxyCurlTask +enum SocksPhase { /** - * DLL for tasks + * We're waiting to get the client hello. */ - struct ProxyCurlTask *prev; + SOCKS5_INIT, /** - * DLL for tasks + * We're waiting to get the initial request. */ - struct ProxyCurlTask *next; + SOCKS5_REQUEST, /** - * Handle to cURL + * We are currently resolving the destination. */ - CURL *curl; + SOCKS5_RESOLVING, /** - * Optional header replacements for curl (LEHO) + * We're in transfer mode. */ - struct curl_slist *headers; + SOCKS5_DATA_TRANSFER, /** - * Optional resolver replacements for curl (LEHO) + * Finish writing the write buffer, then clean up. */ - struct curl_slist *resolver; + SOCKS5_WRITE_THEN_CLEANUP, /** - * curl response code + * Socket has been passed to MHD, do not close it anymore. */ - long curl_response_code; + SOCKS5_SOCKET_WITH_MHD, /** - * The cURL write buffer / MHD read buffer + * We've finished receiving upload data from MHD. */ - char buffer[CURL_MAX_WRITE_SIZE]; + SOCKS5_SOCKET_UPLOAD_STARTED, /** - * Should die. @deprecated + * We've finished receiving upload data from MHD. */ - char url[MAX_HTTP_URI_LENGTH]; + SOCKS5_SOCKET_UPLOAD_DONE, /** - * Read pos of the data in the buffer + * We've finished uploading data via CURL and can now download. */ - char *buffer_read_ptr; + SOCKS5_SOCKET_DOWNLOAD_STARTED, /** - * Write pos in the buffer + * We've finished receiving download data from cURL. */ - char *buffer_write_ptr; + SOCKS5_SOCKET_DOWNLOAD_DONE +}; + + + +/** + * A structure for socks requests + */ +struct Socks5Request +{ /** - * connection + * DLL. */ - struct MHD_Connection *connection; + struct Socks5Request *next; /** - * put + * DLL. */ - size_t put_read_offset; - size_t put_read_size; + struct Socks5Request *prev; /** - *post + * The client socket */ - struct MHD_PostProcessor *post_handler; - - /* post data */ - struct ProxyUploadData *upload_data_head; - struct ProxyUploadData *upload_data_tail; + struct GNUNET_NETWORK_Handle *sock; /** - * the type of POST encoding + * Handle to GNS lookup, during #SOCKS5_RESOLVING phase. */ - char* post_type; - - struct curl_httppost *httppost; - - struct curl_httppost *httppost_last; + struct GNUNET_GNS_LookupRequest *gns_lookup; /** - * Number of bytes in buffer + * Client socket read task */ - unsigned int bytes_in_buffer; - - /* PP task */ - GNUNET_SCHEDULER_TaskIdentifier pp_task; - - /* The associated daemon list entry */ - struct MhdHttpList *mhd; - - /* The associated response */ - struct MHD_Response *response; - - /* Cookies to set */ - struct ProxySetCookieHeader *set_cookies_head; - - /* Cookies to set */ - struct ProxySetCookieHeader *set_cookies_tail; + GNUNET_SCHEDULER_TaskIdentifier rtask; /** - * The authority of the corresponding host (site of origin) + * Client socket write task */ - char authority[256]; + GNUNET_SCHEDULER_TaskIdentifier wtask; /** - * The hostname (Host header field) + * Timeout task */ - char host[256]; + GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** - * The LEgacy HOstname (can be empty) + * Read buffer */ - char leho[256]; + char rbuf[SOCKS_BUFFERSIZE]; /** - * The port + * Write buffer */ - uint16_t port; + char wbuf[SOCKS_BUFFERSIZE]; /** - * The buffer status (BUF_WAIT_FOR_CURL or BUF_WAIT_FOR_MHD) + * Buffer we use for moving data between MHD and curl (in both directions). */ - enum BufferStatus buf_status; + char io_buf[IO_BUFFERSIZE]; /** - * connection status + * MHD HTTP instance handling this request, NULL for none. */ - int ready_to_queue; + struct MhdHttpList *hd; /** - * is curl running? + * MHD response object for this request. */ - int curl_running; - + struct MHD_Response *response; + /** - * are we done + * the domain name to server (only important for SSL) */ - int fin; + char *domain; /** - * Already accepted + * DNS Legacy Host Name as given by GNS, NULL if not given. */ - int accepted; + char *leho; /** - * Indicates wheather the download is in progress + * The URL to fetch */ - int download_in_progress; + char *url; /** - * Indicates wheather the download was successful + * Handle to cURL */ - int download_is_finished; + CURL *curl; /** - * Indicates wheather the download failed + * HTTP request headers for the curl request. */ - int download_error; - - int post_done; - - int is_httppost; + struct curl_slist *headers; -}; - - -/** - * Struct for set-cookies - */ -struct ProxySetCookieHeader -{ /** - * DLL + * HTTP response code to give to MHD for the response. */ - struct ProxySetCookieHeader *next; + unsigned int response_code; /** - * DLL + * Number of bytes already in read buffer */ - struct ProxySetCookieHeader *prev; + size_t rbuf_len; /** - * the cookie + * Number of bytes already in write buffer */ - char *cookie; -}; - - -/** - * Post data structure - */ -struct ProxyUploadData -{ + size_t wbuf_len; + /** - * DLL + * Number of bytes already in the IO buffer. */ - struct ProxyUploadData *next; + size_t io_len; /** - * DLL + * Once known, what's the target address for the connection? */ - struct ProxyUploadData *prev; - - char *key; - - char *filename; - - char *content_type; + struct sockaddr_storage destination_address; - size_t content_length; - /** - * value + * The socks state */ - char *value; + enum SocksPhase state; /** - * to copy + * Desired destination port. */ - size_t bytes_left; + uint16_t port; - /** - * size - */ - size_t total_bytes; }; + /* *********************** Globals **************************** */ @@ -786,16 +597,6 @@ static CURLM *curl_multi; static struct GNUNET_GNS_Handle *gns_handle; /** - * DLL for ProxyCurlTasks - */ -static struct ProxyCurlTask *ctasks_head; - -/** - * DLL for ProxyCurlTasks - */ -static struct ProxyCurlTask *ctasks_tail; - -/** * DLL for http/https daemons */ static struct MhdHttpList *mhd_httpd_head; @@ -873,6 +674,15 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg; static void cleanup_s5r (struct Socks5Request *s5r) { + if (NULL != s5r->curl) + { + curl_multi_remove_handle (curl_multi, s5r->curl); + curl_easy_cleanup (s5r->curl); + s5r->curl = NULL; + } + curl_slist_free_all (s5r->headers); + if (NULL != s5r->response) + MHD_destroy_response (s5r->response); if (GNUNET_SCHEDULER_NO_TASK != s5r->rtask) GNUNET_SCHEDULER_cancel (s5r->rtask); if (GNUNET_SCHEDULER_NO_TASK != s5r->timeout_task) @@ -907,384 +717,191 @@ static void run_mhd_now (struct MhdHttpList *hd); -/* *************************** netcat mode *********************** */ - -#if 0 - - +/* ************************* HTTP handling with cURL *********************** */ /** - * Given a TCP stream and a destination address, forward the stream - * in both directions. + * Callback for MHD response generation. This function is called from + * MHD whenever MHD expects to get data back. Copies data from the + * io_buf, if available. * - * @param cls FIXME - * @param tc FIXME + * @param cls closure with our `struct Socks5Request` + * @param pos in buffer + * @param buf where to copy data + * @param max available space in @a buf + * @return number of bytes written to @a buf */ -static void -forward_socket_like_ncat (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct hostent *phost; - uint32_t remote_ip; - struct sockaddr_in remote_addr; - struct in_addr *r_sin_addr; - - s5r->remote_sock = GNUNET_NETWORK_socket_create (AF_INET, - SOCK_STREAM, - 0); - r_sin_addr = (struct in_addr*)(phost->h_addr); - remote_ip = r_sin_addr->s_addr; - memset(&remote_addr, 0, sizeof(remote_addr)); - remote_addr.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - remote_addr.sin_len = sizeof (remote_addr); -#endif - remote_addr.sin_addr.s_addr = remote_ip; - remote_addr.sin_port = *port; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "target server: %s:%u\n", - inet_ntoa(remote_addr.sin_addr), - ntohs(*port)); - - if ((GNUNET_OK != - GNUNET_NETWORK_socket_connect ( s5r->remote_sock, - (const struct sockaddr*)&remote_addr, - sizeof (remote_addr))) - && (errno != EINPROGRESS)) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect"); - signal_socks_failure (s5r, - SOCKS5_STATUS_NETWORK_UNREACHABLE); - return; - } -} -#endif - - -/* ************************* HTTP handling with cURL *********************** */ - -static int -con_post_data_iter (void *cls, - enum MHD_ValueKind kind, - const char *key, - const char *filename, - const char *content_type, - const char *transfer_encoding, - const char *data, - uint64_t off, - size_t size) +static ssize_t +mhd_content_cb (void *cls, + uint64_t pos, + char* buf, + size_t max) { - struct ProxyCurlTask* ctask = cls; - struct ProxyUploadData* pdata; - char* enc; - char* new_value; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got POST data (file: %s, content type: %s): '%s=%.*s' at offset %llu size %llu\n", - filename, content_type, - key, (int) size, data, - (unsigned long long) off, - (unsigned long long) size); - 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_new (struct ProxyUploadData); - pdata->key = GNUNET_strdup (key); - - if (NULL != filename) - pdata->filename = GNUNET_strdup (filename); - if (NULL != content_type) - pdata->content_type = GNUNET_strdup (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 %llu bytes of POST Data\n", - (unsigned long long) 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) - { - enc = curl_easy_escape (ctask->curl, key, 0); - if (NULL == enc) - { - GNUNET_break (0); - return MHD_NO; - } - /* a key */ - pdata = GNUNET_new (struct ProxyUploadData); - pdata->value = GNUNET_malloc (strlen (enc) + 3); - if (NULL != ctask->upload_data_head) - { - pdata->value[0] = '&'; - memcpy (pdata->value+1, enc, strlen (enc)); - } - else - memcpy (pdata->value, enc, strlen (enc)); - pdata->value[strlen (pdata->value)] = '='; - pdata->bytes_left = strlen (pdata->value); - pdata->total_bytes = pdata->bytes_left; - curl_free (enc); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Escaped POST key: '%s'\n", - pdata->value); - - GNUNET_CONTAINER_DLL_insert_tail (ctask->upload_data_head, - ctask->upload_data_tail, - pdata); - } - - /* a value */ - enc = curl_easy_escape (ctask->curl, data, 0); - if (NULL == enc) - { - GNUNET_break (0); - return MHD_NO; - } - pdata = GNUNET_new (struct ProxyUploadData); - pdata->value = GNUNET_malloc (strlen (enc) + 1); - memcpy (pdata->value, enc, strlen (enc)); - pdata->bytes_left = strlen (pdata->value); - pdata->total_bytes = pdata->bytes_left; - curl_free (enc); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Escaped POST value: '%s'\n", - pdata->value); - - GNUNET_CONTAINER_DLL_insert_tail (ctask->upload_data_head, - ctask->upload_data_tail, - pdata); - return MHD_YES; + struct Socks5Request *s5r = cls; + size_t bytes_to_copy; + + if ( (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) || + (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) ) + { + /* we're still not done with the upload, do not yet + start the download, the IO buffer is still full + with upload data. */ + return 0; /* not yet ready for data download */ + } + bytes_to_copy = GNUNET_MIN (max, + s5r->io_len); + if ( (0 == bytes_to_copy) && + (SOCKS5_SOCKET_DOWNLOAD_DONE != s5r->state) ) + return 0; /* more data later */ + if ( (0 == bytes_to_copy) && + (SOCKS5_SOCKET_DOWNLOAD_DONE == s5r->state) ) + return MHD_CONTENT_READER_END_OF_STREAM; + memcpy (buf, s5r->io_buf, bytes_to_copy); + memmove (s5r->io_buf, + &s5r->io_buf[bytes_to_copy], + s5r->io_len - bytes_to_copy); + s5r->io_len -= bytes_to_copy; + curl_easy_pause (s5r->curl, CURLPAUSE_CONT); + return bytes_to_copy; } /** - * Read HTTP request header field 'Host' + * Check that the website has presented us with a valid SSL certificate. + * The certificate must either match the domain name or the LEHO name + * (or, if available, the TLSA record). * - * @param cls buffer to write to - * @param kind value kind - * @param key field key - * @param value field value - * @return #MHD_NO when Host found + * @param s5r request to check for. + * @return #GNUNET_OK if the certificate is valid */ static int -con_val_iter (void *cls, - enum MHD_ValueKind kind, - const char *key, - const char *value) +check_ssl_certificate (struct Socks5Request *s5r) { - struct ProxyCurlTask *ctask = cls; - char* buf = ctask->host; - char* port; - char* cstr; - const char* hdr_val; - unsigned int uport; - - if (0 == strcmp ("Host", key)) - { - port = strchr (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; + union { + struct curl_slist *to_info; + struct curl_certinfo *to_certinfo; + } ptr; + int i; + struct curl_slist *slist; + + ptr.to_info = NULL; + if (CURLE_OK != + curl_easy_getinfo (s5r->curl, + CURLINFO_CERTINFO, + &ptr.to_info)) + return GNUNET_SYSERR; + /* FIXME: for now, we just output the certs to stderr */ + if(NULL != ptr.to_info) + { + fprintf (stderr, + "Got %d certs!\n", + ptr.to_certinfo->num_of_certs); + for (i = 0; i < ptr.to_certinfo->num_of_certs; i++) + { + for (slist = ptr.to_certinfo->certinfo[i]; NULL != slist; slist = slist->next) + fprintf (stderr, + "%d: %s\n", + i, + slist->data); } - else - strcpy (buf, value); - return MHD_YES; } - - if (0 == strcmp (MHD_HTTP_HEADER_ACCEPT_ENCODING, key)) - hdr_val = ""; - 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); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Client Header: %s\n", cstr); - - ctask->headers = curl_slist_append (ctask->headers, cstr); - GNUNET_free (cstr); - - return MHD_YES; + return GNUNET_OK; } + /** - * Callback for MHD response - * - * @param cls closure - * @param pos in buffer - * @param buf buffer - * @param max space in buffer - * @return number of bytes written - */ -static ssize_t -mhd_content_cb (void *cls, - uint64_t pos, - char* buf, - size_t max); - - -/** - * Check HTTP response header for mime + * We're getting an HTTP response header from cURL. Convert it to the + * MHD response headers. Mostly copies the headers, but makes special + * adjustments to "Set-Cookie" and "Location" headers as those may need + * to be changed from the LEHO to the domain the browser expects. * - * @param buffer curl buffer + * @param buffer curl buffer with a single line of header data; not 0-terminated! * @param size curl blocksize * @param nmemb curl blocknumber - * @param cls handle - * @return size of read bytes + * @param cls our `struct Socks5Request *` + * @return size of processed bytes */ static size_t curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) { + struct Socks5Request *s5r = cls; size_t bytes = size * nmemb; - struct ProxyCurlTask *ctask = cls; - int cookie_hdr_len = strlen (MHD_HTTP_HEADER_SET_COOKIE); - char hdr_generic[bytes+1]; - char new_cookie_hdr[bytes+strlen (ctask->leho)+1]; - char new_location[MAX_HTTP_URI_LENGTH+500]; - char real_host[264]; - char leho_host[264]; - char* ndup; - char* tok; - char* cookie_domain; - char* hdr_type; - char* hdr_val; - int delta_cdomain; - size_t offset = 0; - char cors_hdr[strlen (ctask->leho) + strlen ("https://")]; - - if (NULL == ctask->response) - { - /* FIXME: get total size from curl (if available) */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating response for %s\n", ctask->url); - ctask->response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, - sizeof (ctask->buffer), - &mhd_content_cb, - ctask, - NULL); - - /* if we have a leho add a CORS header */ - if (0 != strcmp ("", ctask->leho)) + char *ndup; + const char *hdr_type; + const char *hdr_val; + long resp_code; + char *new_cookie_hdr; + + if (NULL == s5r->response) + { + /* first, check SSL certificate */ + if ( (HTTPS_PORT == s5r->port) && + (GNUNET_OK != check_ssl_certificate (s5r)) ) + return 0; + + GNUNET_break (CURLE_OK == + curl_easy_getinfo (s5r->curl, + CURLINFO_RESPONSE_CODE, + &resp_code)); + s5r->response_code = resp_code; + s5r->response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, + IO_BUFFERSIZE, + &mhd_content_cb, + s5r, + NULL); + if (NULL != s5r->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); - } + char *cors_hdr; + + GNUNET_asprintf (&cors_hdr, + (HTTPS_PORT == s5r->port) + ? "https://%s" + : "http://%s", + s5r->leho); + + GNUNET_break (MHD_YES == + MHD_add_response_header (s5r->response, + MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, + cors_hdr)); + GNUNET_free (cors_hdr); } - ctask->ready_to_queue = GNUNET_YES; + /* force connection to be closed after each request, as we + do not support HTTP pipelining */ + GNUNET_break (MHD_YES == + MHD_add_response_header (s5r->response, + MHD_HTTP_HEADER_CONNECTION, + "close")); } - if (cookie_hdr_len > bytes) + + ndup = GNUNET_strndup (buffer, bytes); + hdr_type = strtok (ndup, ":"); + if (NULL == hdr_type) + { + GNUNET_free (ndup); return bytes; + } + hdr_val = strtok (NULL, ""); + if (NULL == hdr_val) + { + GNUNET_free (ndup); + return bytes; + } + if (' ' == *hdr_val) + hdr_val++; - memcpy (hdr_generic, buffer, bytes); - hdr_generic[bytes] = '\0'; - /* remove crlf */ - if ('\n' == hdr_generic[bytes-1]) - hdr_generic[bytes-1] = '\0'; - - if (hdr_generic[bytes-2] == '\r') - hdr_generic[bytes-2] = '\0'; - - if (0 == memcmp (hdr_generic, - MHD_HTTP_HEADER_SET_COOKIE, - cookie_hdr_len)) + /* custom logic for certain header types */ + if (0 == strcasecmp (hdr_type, + MHD_HTTP_HEADER_SET_COOKIE)) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Looking for cookie in: `%s'\n", hdr_generic); - ndup = GNUNET_strdup (hdr_generic+cookie_hdr_len+1); - memset (new_cookie_hdr, 0, sizeof (new_cookie_hdr)); - for (tok = strtok (ndup, ";"); tok != NULL; tok = strtok (NULL, ";")) +#if 0 + // FIXME: adjust code... + for (tok = strtok (hdr_val, ";"); NULL != tok; tok = strtok (NULL, ";")) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Got Cookie token: %s\n", tok); - //memcpy (new_cookie_hdr+offset, tok, strlen (tok)); if (0 == memcmp (tok, " domain", strlen (" domain"))) { cookie_domain = tok + strlen (" domain") + 1; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Got Set-Cookie Domain: %s\n", cookie_domain); - - if (strlen (cookie_domain) < strlen (ctask->leho)) + if (strlen (cookie_domain) < strlen (s5r->leho)) { delta_cdomain = strlen (ctask->leho) - strlen (cookie_domain); if (0 == strcmp (cookie_domain, ctask->leho + (delta_cdomain))) @@ -1312,51 +929,26 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) } } GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Cookie domain invalid\n"); - - + "Cookie domain invalid\n"); } - memcpy (new_cookie_hdr+offset, tok, strlen (tok)); + memcpy (new_cookie_hdr + offset, tok, strlen (tok)); offset += strlen (tok); new_cookie_hdr[offset] = ';'; offset++; } - - GNUNET_free (ndup); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Got Set-Cookie HTTP header %s\n", new_cookie_hdr); - - if (GNUNET_NO == MHD_add_response_header (ctask->response, - MHD_HTTP_HEADER_SET_COOKIE, - new_cookie_hdr)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "MHD: Error adding set-cookie header field %s\n", - hdr_generic+cookie_hdr_len+1); - } - return bytes; - } - - ndup = GNUNET_strdup (hdr_generic); - hdr_type = strtok (ndup, ":"); + hdr_val = new_cookie_hdr; - if (NULL == hdr_type) - { - GNUNET_free (ndup); - return bytes; +#else + new_cookie_hdr = NULL; +#endif } - - hdr_val = strtok (NULL, ""); - - if (NULL == hdr_val) + else { - GNUNET_free (ndup); - return bytes; + new_cookie_hdr = NULL; } - hdr_val++; - +#if 0 + /* FIXME: adjust handling */ if (0 == strcasecmp (MHD_HTTP_HEADER_LOCATION, hdr_type)) { if (ctask->mhd->is_ssl) @@ -1376,308 +968,99 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) hdr_val = new_location; } } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Trying to set %s: %s\n", - hdr_type, - hdr_val); - if (GNUNET_NO == MHD_add_response_header (ctask->response, - hdr_type, - hdr_val)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "MHD: Error adding %s header field %s\n", - hdr_type, - hdr_val); - } +#endif + GNUNET_break (MHD_YES == + MHD_add_response_header (s5r->response, + hdr_type, + hdr_val)); GNUNET_free (ndup); + GNUNET_free_non_null (new_cookie_hdr); return bytes; } - -/** - * Ask cURL for the select sets and schedule download - */ -static void -curl_download_prepare (void); - - -/** - * Callback to free content - * - * @param cls content to free - * @param tc task context - */ -static void -mhd_content_free (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct ProxyCurlTask *ctask = cls; - struct ProxyUploadData *pdata; - - if (NULL != ctask->headers) - curl_slist_free_all (ctask->headers); - - if (NULL != ctask->headers) - curl_slist_free_all (ctask->resolver); - - if (NULL != ctask->response) - MHD_destroy_response (ctask->response); - - if (NULL != ctask->post_handler) - MHD_destroy_post_processor (ctask->post_handler); - - if (GNUNET_SCHEDULER_NO_TASK != ctask->pp_task) - GNUNET_SCHEDULER_cancel (ctask->pp_task); - - 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); -} - - -/** - * Callback for MHD response - * - * @param cls closure - * @param pos in buffer - * @param buf buffer - * @param max space in buffer - * @return number of bytes written - */ -static ssize_t |