gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r27484 - libmicrohttpd/src/spdy2http


From: gnunet
Subject: [GNUnet-SVN] r27484 - libmicrohttpd/src/spdy2http
Date: Wed, 19 Jun 2013 11:34:15 +0200

Author: andreyu
Date: 2013-06-19 11:34:15 +0200 (Wed, 19 Jun 2013)
New Revision: 27484

Modified:
   libmicrohttpd/src/spdy2http/proxy.c
Log:
spdy2http: added options

Modified: libmicrohttpd/src/spdy2http/proxy.c
===================================================================
--- libmicrohttpd/src/spdy2http/proxy.c 2013-06-19 09:28:45 UTC (rev 27483)
+++ libmicrohttpd/src/spdy2http/proxy.c 2013-06-19 09:34:15 UTC (rev 27484)
@@ -21,6 +21,9 @@
  * @brief   Translates incoming SPDY requests to http server on localhost.
  *                     Uses libcurl.
  *                     No error handling for curl requests.
+ *      TODO:
+ * - test all options!
+ * - don't abort on lack of memory
  * @author Andrey Uzunov
  */
  
@@ -36,8 +39,38 @@
 #include "microspdy.h"
 #include <curl/curl.h>
 #include <assert.h>
+#include <getopt.h>
+#include <regex.h>
 
 
+struct global_options
+{
+  char *http_backend;
+  char *cert;
+  char *cert_key;
+  uint16_t listen_port;
+  bool verbose;
+  bool curl_verbose;
+  bool transparent;
+  bool http10;
+} glob_opt;
+
+
+struct URI
+{
+  char * full_uri;
+  char * scheme;
+  char * host_and_port;
+  //char * host_and_port_for_connecting;
+  char * host;
+  char * path;
+  char * path_and_more;
+  char * query;
+  char * fragment;
+  uint16_t port;
+};
+
+
 #define PRINT_INFO(msg) do{\
        printf("%i:%s\n", __LINE__, msg);\
        fflush(stdout);\
@@ -54,6 +87,26 @@
        while(0)
 
 
+#define PRINT_VERBOSE(msg) do{\
+  if(glob_opt.verbose){\
+       printf("%i:%s\n", __LINE__, msg);\
+       fflush(stdout);\
+       }\
+  }\
+       while(0)
+
+
+#define PRINT_VERBOSE2(fmt, ...) do{\
+  if(glob_opt.verbose){\
+       printf("%i\n", __LINE__);\
+       printf(fmt,##__VA_ARGS__);\
+       printf("\n");\
+       fflush(stdout);\
+       }\
+       }\
+       while(0)
+
+
 #define CURL_SETOPT(handle, opt, val) do{\
        int ret; \
        if(CURLE_OK != (ret = curl_easy_setopt(handle, opt, val))) \
@@ -63,17 +116,25 @@
        } \
        }\
        while(0)
+  
 
+#define DIE(msg) do{\
+       printf("FATAL ERROR (line %i): %s\n", __LINE__, msg);\
+       fflush(stdout);\
+  exit(EXIT_FAILURE);\
+       }\
+       while(0)
 
-int run = 1;
-char* http_host;
+
+int loop = 1;
 CURLM *multi_handle;
 int still_running = 0; /* keep number of running handles */
-int http10=0;
+regex_t uri_preg;
 
+
 struct Proxy
 {
-       char *path;
+       char *url;
        struct SPDY_Request *request;
        struct SPDY_Response *response;
        CURL *curl_handle;
@@ -89,6 +150,114 @@
 };
 
 
+void
+free_uri(struct URI * uri)
+{
+  if(NULL != uri)
+  {
+    free(uri->full_uri);
+    free(uri->scheme);
+    free(uri->host_and_port);
+    //free(uri->host_and_port_for_connecting);
+    free(uri->host);
+    free(uri->path);
+    free(uri->path_and_more);
+    free(uri->query);
+    free(uri->fragment);
+    uri->port = 0;
+    free(uri);
+  }
+}
+
+int
+init_parse_uri(regex_t * preg)
+{
+  // RFC 2396
+  // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+      /*
+        scheme    = $2
+      authority = $4
+      path      = $5
+      query     = $7
+      fragment  = $9
+      */
+  
+  return regcomp(preg, 
"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?", REG_EXTENDED);
+}
+
+void
+deinit_parse_uri(regex_t * preg)
+{
+  regfree(preg);
+}
+  
+int
+parse_uri(regex_t * preg, char * full_uri, struct URI ** uri)
+{
+  int ret;
+  char *colon;
+  long long port;
+  size_t nmatch = 10;
+  regmatch_t pmatch[10];
+
+  if (0 != (ret = regexec(preg, full_uri, nmatch, pmatch, 0)))
+    return ret;
+    
+  *uri = malloc(sizeof(struct URI));
+  if(NULL == *uri)
+    return -200;
+    
+  (*uri)->full_uri = strdup(full_uri);
+  
+  asprintf(&((*uri)->scheme), "%.*s",pmatch[2].rm_eo - pmatch[2].rm_so, 
&full_uri[pmatch[2].rm_so]);
+  asprintf(&((*uri)->host_and_port), "%.*s",pmatch[4].rm_eo - pmatch[4].rm_so, 
&full_uri[pmatch[4].rm_so]);
+  asprintf(&((*uri)->path), "%.*s",pmatch[5].rm_eo - pmatch[5].rm_so, 
&full_uri[pmatch[5].rm_so]);
+  asprintf(&((*uri)->path_and_more), "%.*s",pmatch[9].rm_eo - pmatch[5].rm_so, 
&full_uri[pmatch[5].rm_so]);
+  asprintf(&((*uri)->query), "%.*s",pmatch[7].rm_eo - pmatch[7].rm_so, 
&full_uri[pmatch[7].rm_so]);
+  asprintf(&((*uri)->fragment), "%.*s",pmatch[9].rm_eo - pmatch[9].rm_so, 
&full_uri[pmatch[9].rm_so]);
+  
+  colon = strrchr((*uri)->host_and_port, ':');
+  if(NULL == colon)
+  {
+    (*uri)->host = strdup((*uri)->host_and_port);
+    /*if(0 == strcasecmp("http", uri->scheme))
+    {
+      uri->port = 80;
+      asprintf(&(uri->host_and_port_for_connecting), "%s:80", 
uri->host_and_port);
+    }
+    else if(0 == strcasecmp("https", uri->scheme))
+    {
+      uri->port = 443;
+      asprintf(&(uri->host_and_port_for_connecting), "%s:443", 
uri->host_and_port);
+    }
+    else
+    {
+      PRINT_INFO("no standard scheme!");
+      */(*uri)->port = 0;
+      /*uri->host_and_port_for_connecting = strdup(uri->host_and_port);
+    }*/
+    return 0;
+  }
+  
+  port = atoi(colon  + 1);
+  if(port<1 || port >= 256 * 256)
+  {
+    free_uri(*uri);
+    return -100;
+  }
+  (*uri)->port = port;
+  asprintf(&((*uri)->host), "%.*s", (int)(colon - (*uri)->host_and_port), 
(*uri)->host_and_port);
+  
+  return 0;
+}
+
+
+static void catch_signal(int signal)
+{
+  loop = 0;
+}
+
+
 ssize_t
 response_callback (void *cls,
                                                void *buffer,
@@ -146,10 +315,6 @@
        struct Proxy *proxy = (struct Proxy *)cls;
        int ret;
        
-       //printf("response_done_callback\n");
-       
-       //printf("answer for %s was sent\n", (char *)cls);
-       
        if(SPDY_RESPONSE_RESULT_SUCCESS != status)
        {
                printf("answer was NOT sent, %i\n",status);
@@ -163,8 +328,7 @@
        
        SPDY_destroy_request(request);
        SPDY_destroy_response(response);
-       if(!strcmp("/close",proxy->path)) run = 0;
-       free(proxy->path);
+       free(proxy->url);
        free(proxy);
 }
 
@@ -200,10 +364,7 @@
                                                        &response_callback,
                                                        proxy,
                                                        0)))
-               {
-                       PRINT_INFO("no response");
-                       abort();
-               }
+                       DIE("no response");
     
                SPDY_name_value_destroy(proxy->headers);
                free(proxy->status_msg);
@@ -215,10 +376,7 @@
                                                        false,
                                                        &response_done_callback,
                                                        proxy))
-               {
-                       PRINT_INFO("no queue");
-                       abort();
-               }
+                       DIE("no queue");
                
                return realsize;
        }
@@ -230,24 +388,15 @@
                //version
                for(i=pos; i<realsize && ' '!=line[i]; ++i);
                if(i == realsize)
-               {
-                       PRINT_INFO("error on parsing headers");
-                       abort();
-               }
+                       DIE("error on parsing headers");
                if(NULL == (proxy->version = strndup(line, i - pos)))
-               {
-                       PRINT_INFO("no memory");
-                       abort();
-               }
+        DIE("No memory");
                pos = i+1;
                
                //status (number)
                for(i=pos; i<realsize && ' '!=line[i] && '\r'!=line[i]; ++i);
                if(NULL == (status = strndup(&(line[pos]), i - pos)))
-               {
-                       PRINT_INFO("no memory");
-                       abort();
-               }
+        DIE("No memory");
                proxy->status = atoi(status);
                free(status);
                if(i<realsize && '\r'!=line[i])
@@ -256,10 +405,7 @@
                        pos = i+1;
                        for(i=pos; i<realsize && '\r'!=line[i]; ++i);
                        if(NULL == (proxy->status_msg = strndup(&(line[pos]), i 
- pos)))
-                       {
-                               PRINT_INFO("no memory");
-                               abort();
-                       }
+        DIE("No memory");
                }
                return realsize;
        }
@@ -269,10 +415,7 @@
        for(i=pos; i<realsize && ':'!=line[i] && '\r'!=line[i]; ++i)
                line[i] = tolower(line[i]); //spdy requires lower case
        if(NULL == (name = strndup(line, i - pos)))
-       {
-               PRINT_INFO("no memory");
-               abort();
-       }
+        DIE("No memory");
        if(0 == strcmp(SPDY_HTTP_HEADER_CONNECTION, name)
                || 0 == strcmp(SPDY_HTTP_HEADER_KEEP_ALIVE, name))
        {
@@ -284,10 +427,7 @@
        {
                //no value. is it possible?
                if(SPDY_YES != SPDY_name_value_add(proxy->headers, name, ""))
-               {
-                       PRINT_INFO("SPDY_name_value_add failed");
-                       abort();
-               }
+                       DIE("SPDY_name_value_add failed");
                return realsize;
        }
        
@@ -296,10 +436,7 @@
        while(pos<realsize && isspace(line[pos])) ++pos; //remove leading space
        for(i=pos; i<realsize && '\r'!=line[i]; ++i);
        if(NULL == (value = strndup(&(line[pos]), i - pos)))
-       {
-               PRINT_INFO("no memory");
-               abort();
-       }
+        DIE("No memory");
        if(SPDY_YES != (ret = SPDY_name_value_add(proxy->headers, name, value)))
        {
     abort_it=true;
@@ -365,12 +502,8 @@
                line_len += strlen(value[i]);
        }
        
-       if(NULL == (line = malloc(line_len)))
-       {
-               //no recovory
-               PRINT_INFO("no memory");
-               abort();
-       }
+       if(NULL == (line = malloc(line_len)))//no recovery
+    DIE("No memory");
        line[0] = 0;
     
     strcat(line, name);
@@ -384,11 +517,8 @@
                if(i) strcat(line, ", ");
                strcat(line, value[i]);
        }
-    if(NULL == (*curl_headers = curl_slist_append(*curl_headers, line)))
-    {
-               PRINT_INFO("curl_slist_append failed");
-               abort();
-       }
+  if(NULL == (*curl_headers = curl_slist_append(*curl_headers, line)))
+               DIE("curl_slist_append failed");
        free(line);
        
        return SPDY_YES;
@@ -411,43 +541,54 @@
        (void)host;
        (void)scheme;
        
-       char *url;
        struct Proxy *proxy;
        int ret;
+  struct URI *uri;
        
-       //printf("received request for '%s %s %s'\n", method, path, version);
+       PRINT_VERBOSE2("received request for '%s %s %s'\n", method, path, 
version);
        if(NULL == (proxy = malloc(sizeof(struct Proxy))))
-       {
-               PRINT_INFO("No memory");
-               abort();
-       }
+        DIE("No memory");
        memset(proxy, 0, sizeof(struct Proxy));
        proxy->request = request;
        if(NULL == (proxy->headers = SPDY_name_value_create()))
-       {
-               PRINT_INFO("No memory");
-               abort();
-       }
-       
-  //TODO add https
-       if(0 == strcmp(http_host, "any"))
-               ret = asprintf(&url,"%s%s%s","http://";, host, path);
-       else
-               ret = asprintf(&url,"%s%s%s","http://";, http_host, path);
-               
-       if(-1 == ret)
-       {
-               PRINT_INFO("No memory");
-               abort();
-       }
-       
-       if(NULL == (proxy->path = strdup(path)))
-       {
-               PRINT_INFO("No memory");
-               abort();
-       }
+        DIE("No memory");
+  
+  if(glob_opt.transparent)
+  {
+    if(NULL != glob_opt.http_backend) //use always same host
+      ret = asprintf(&(proxy->url),"%s://%s%s", scheme, glob_opt.http_backend, 
path);
+    else //use host header
+      ret = asprintf(&(proxy->url),"%s://%s%s", scheme, host, path);
+    if(-1 == ret)
+        DIE("No memory");
+        
+    ret = parse_uri(&uri_preg, proxy->url, &uri);
+    if(ret != 0)
+      DIE("parsing built uri failed");
+  }
+  else
+  {
+    ret = parse_uri(&uri_preg, path, &uri);
+    PRINT_INFO2("path %s '%s' '%s'", path, uri->scheme, uri->host);
+    if(ret != 0 || !strlen(uri->scheme) || !strlen(uri->host))
+      DIE("parsing received uri failed");
+      
+    if(NULL != glob_opt.http_backend) //use backend host
+    {
+      ret = asprintf(&(proxy->url),"%s://%s%s", uri->scheme, 
glob_opt.http_backend, uri->path_and_more);
+      if(-1 == ret)
+        DIE("No memory");
+    }
+    else //use request path
+      if(NULL == (proxy->url = strdup(path)))
+        DIE("No memory");
+  }
+  
+  free(uri);
+  
+  PRINT_VERBOSE2("curl will request '%s'", proxy->url);
     
-    SPDY_name_value_iterate(headers, &iterate_cb, proxy);
+  SPDY_name_value_iterate(headers, &iterate_cb, proxy);
        
        if(NULL == (proxy->curl_handle = curl_easy_init()))
     {
@@ -455,10 +596,10 @@
                abort();
        }
        
-       //CURL_SETOPT(proxy->curl_handle, CURLOPT_VERBOSE, 1);
-       CURL_SETOPT(proxy->curl_handle, CURLOPT_URL, url);
-       free(url);
-       if(http10)
+       if(glob_opt.curl_verbose)
+    CURL_SETOPT(proxy->curl_handle, CURLOPT_VERBOSE, 1);
+       CURL_SETOPT(proxy->curl_handle, CURLOPT_URL, proxy->url);
+       if(glob_opt.http10)
                CURL_SETOPT(proxy->curl_handle, CURLOPT_HTTP_VERSION, 
CURL_HTTP_VERSION_1_0);
        CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEFUNCTION, curl_write_cb);
        CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEDATA, proxy);
@@ -484,9 +625,9 @@
 }
 
 int
-main (int argc, char *const *argv)
-{      
-       unsigned long long timeoutlong=0;
+run()
+{
+  unsigned long long timeoutlong=0;
   long curl_timeo = -1;
        struct timeval timeout;
        int ret;
@@ -504,20 +645,18 @@
 
        signal(SIGPIPE, SIG_IGN);
        
-       if(argc != 6)
-       {
-               printf("Usage: %s cert-file key-file host port 
http/1.0(yes/no)\n\
-\n\
-Example for transparent proxy (':host' header is used to know which HTTP 
server to connect):\n\
-%s cert.pem key.pem any 8080 no\n", argv[0], argv[0]);
-               return 1;
-       }
-       
+  if (signal(SIGINT, catch_signal) == SIG_ERR)
+    PRINT_VERBOSE("signal failed");
+    
+  srand(time(NULL));
+  if(init_parse_uri(&uri_preg))
+    DIE("Regexp compilation failed");
+    
        SPDY_init();
        
-       daemon = SPDY_start_daemon(atoi(argv[4]),
-                                                               argv[1],
-                                                               argv[2],
+       daemon = SPDY_start_daemon(glob_opt.listen_port,
+                                                               glob_opt.cert,
+                                                               
glob_opt.cert_key,
                                                                NULL,
                                                                NULL,
                                                                
&standard_request_handler,
@@ -533,21 +672,13 @@
        }
        
        multi_handle = curl_multi_init();
-       
-       if(NULL==multi_handle){
-               PRINT_INFO("no multi_handle");
-               abort();
-       }
-       
-       if(!strcmp("yes", argv[5]))
-               http10 = 1;
-       
-       http_host = argv[3];
+       if(NULL==multi_handle)
+               DIE("no multi_handle");
+  
        timeout.tv_usec = 0;
 
        do
        {
-               //printf("still %i\n", still_running);
                FD_ZERO(&rs);
                FD_ZERO(&ws);
                FD_ZERO(&es);
@@ -653,14 +784,129 @@
       else PRINT_INFO("shouldn't happen");
     }
   }
-  while(run);
+  while(loop);
        
        curl_multi_cleanup(multi_handle);
 
        SPDY_stop_daemon(daemon);
        
        SPDY_deinit();
+  
+  deinit_parse_uri(&uri_preg);
        
        return 0;
 }
 
+void
+display_usage()
+{
+  printf(
+    "Usage: microspdy2http [-vh0t] [-b <HTTP-SERVER>] -p <PORT> -c 
<CERTIFICATE> -k <CERT-KEY>\n\n"
+    "OPTIONS:\n"
+    "    -p, --port            Listening port.\n"
+    "    -c, --certificate     Path to a certificate file.\n"
+    "    -k, --certificate-key Path to a key file for the certificate.\n"
+    "    -b, --backend-server  If set, the proxy will connect always to it.\n"
+    "                          Otherwise the proxy will connect to the URL\n"
+    "                          which is specified in the path or 'Host:'.\n"
+    "    -v, --verbose         Print debug information.\n"
+    "    -h, --curl-verbose    Print debug information for curl.\n"
+    "    -0, --http10          Prefer HTTP/1.0 connections to the next hop.\n"
+    "    -t, --transparent     If set, the proxy will fetch an URL which\n"
+    "                          is based on 'Host:' header and requested 
path.\n"
+    "                          Otherwise, full URL in the requested path is 
required.\n\n"
+
+  );
+}
+
+int
+main (int argc, char *const *argv)
+{      
+         
+  int getopt_ret;
+  int option_index;
+  struct option long_options[] = {
+    {"port",  required_argument, 0, 'p'},
+    {"certificate",  required_argument, 0, 'c'},
+    {"certificate-key",  required_argument, 0, 'k'},
+    {"backend-server",  required_argument, 0, 'b'},
+    {"verbose",  no_argument, 0, 'v'},
+    {"curl-verbose",  no_argument, 0, 'h'},
+    {"http10",  no_argument, 0, '0'},
+    {"transparent",  no_argument, 0, 't'},
+    {0, 0, 0, 0}
+  };
+  
+  while (1)
+  {
+    getopt_ret = getopt_long( argc, argv, "p:c:k:b:v0t", long_options, 
&option_index);
+    if (getopt_ret == -1)
+      break;
+
+    switch(getopt_ret)
+    {
+      case 'p':
+        glob_opt.listen_port = atoi(optarg);
+        break;
+        
+      case 'c':
+        glob_opt.cert = strdup(optarg);
+        if(NULL == glob_opt.cert)
+          return 1;
+        break;
+        
+      case 'k':
+        glob_opt.cert_key = strdup(optarg);
+        if(NULL == glob_opt.cert_key)
+          return 1;
+        break;
+        
+      case 'b':
+        glob_opt.http_backend = strdup(optarg);
+        if(NULL == glob_opt.http_backend)
+          return 1;
+        break;
+        
+      case 'v':
+        glob_opt.verbose = true;
+        break;
+        
+      case 'h':
+        glob_opt.curl_verbose = true;
+        break;
+        
+      case '0':
+        glob_opt.http10 = true;
+        break;
+        
+      case 't':
+        glob_opt.transparent = true;
+        break;
+        
+      case 0:
+        PRINT_INFO("0 from getopt");
+        break;
+        
+      case '?':
+        display_usage();
+        return 1;
+        
+      default:
+        DIE("default from getopt");
+    }
+  }
+  
+  if(
+    0 == glob_opt.listen_port
+    || NULL == glob_opt.cert
+    || NULL == glob_opt.cert_key
+    //|| !glob_opt.transparent && NULL != glob_opt.http_backend
+    )
+  {
+    display_usage();
+    return 1;
+  }
+    
+  return run();
+}
+




reply via email to

[Prev in Thread] Current Thread [Next in Thread]