iodine 0.4.7 → 0.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +8 -0
 - data/README.md +1 -1
 - data/ext/iodine/http.c +34 -4
 - data/ext/iodine/http.h +8 -0
 - data/ext/iodine/http1.c +269 -160
 - data/ext/iodine/http1_parser.c +276 -0
 - data/ext/iodine/http1_parser.h +111 -0
 - data/ext/iodine/http1_response.c +8 -8
 - data/ext/iodine/http_response.c +1 -16
 - data/lib/iodine/version.rb +1 -1
 - metadata +4 -4
 - data/ext/iodine/http1_simple_parser.c +0 -496
 - data/ext/iodine/http1_simple_parser.h +0 -68
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: '08f011b1bc43d3c47d266fc0e2dab7379708e5de'
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 1197234946e68f0515ce51d3f8858d948a0a77ef
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: aab2abfb29dea3efd0041c31abfbe93b3aac2fa21cf48fa48629263d58d6b636ff054d43acc33b3c7e24904a7240e42ef6e865218b1530bce530bf785adc4ef6
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 4ed2825719fc986132ecbdb28d3c56c2bc23e752f1d67df794a92fc12c5f89c84c0b914ef7ad49bece19d2f01ac3790ddce73b858fe024a1fffaeab985eba6aa
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -6,6 +6,14 @@ Please notice that this change log contains changes for upcoming releases as wel 
     | 
|
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            ## Changes:
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
      
 9 
     | 
    
         
            +
            #### Change log v.0.4.8
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            **Change**: (`facil.io`) the internal HTTP parser was replaced with something easier to read, for maintainability reasons. Performance seems to be unaffected.
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            **Fix**: HTTP request logging included an extra info line which was a debug/testing message inherited from `facil.io` v.0.5.3-pre-release. This is now removed.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            **Performance**: The `now` HTTP Date string is now cached for up to 2 seconds, improving performance for `Date`, `Last-Modified` and Iodine logging messages that relate to the current time. However, it's likely that Rack will write it's own date string, masking this feature.
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
       9 
17 
     | 
    
         
             
            #### Change log v.0.4.7
         
     | 
| 
       10 
18 
     | 
    
         | 
| 
       11 
19 
     | 
    
         
             
            **Update**: Now using `facil.io` edge (stripped down v.0.5.3).
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -399,7 +399,7 @@ Yes, please, here are some thoughts: 
     | 
|
| 
       399 
399 
     | 
    
         | 
| 
       400 
400 
     | 
    
         
             
            * If we can write a Java wrapper for [the `facil.io` C framework](https://github.com/boazsegev/facil.io), it would be nice... but it could be as big a project as the whole gem, as a lot of minor details are implemented within the bridge between these two languages.
         
     | 
| 
       401 
401 
     | 
    
         | 
| 
       402 
     | 
    
         
            -
            * PRs or issues related to [the `facil.io` C framework](https://github.com/boazsegev/facil.io)  
     | 
| 
      
 402 
     | 
    
         
            +
            * PRs or issues related to [the `facil.io` C framework](https://github.com/boazsegev/facil.io) should be placed in [the `facil.io` repository](https://github.com/boazsegev/facil.io).
         
     | 
| 
       403 
403 
     | 
    
         | 
| 
       404 
404 
     | 
    
         
             
            * Bug reports and pull requests are welcome on GitHub at https://github.com/boazsegev/iodine.
         
     | 
| 
       405 
405 
     | 
    
         | 
    
        data/ext/iodine/http.c
    CHANGED
    
    | 
         @@ -121,7 +121,7 @@ struct tm *http_gmtime(const time_t *timer, struct tm *tmbuf) { 
     | 
|
| 
       121 
121 
     | 
    
         
             
              // static char * Months = {  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
         
     | 
| 
       122 
122 
     | 
    
         
             
              // "Jul",
         
     | 
| 
       123 
123 
     | 
    
         
             
              // "Aug", "Sep", "Oct", "Nov", "Dec"};
         
     | 
| 
       124 
     | 
    
         
            -
              static uint8_t month_len[] = {
         
     | 
| 
      
 124 
     | 
    
         
            +
              static const uint8_t month_len[] = {
         
     | 
| 
       125 
125 
     | 
    
         
             
                  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, // nonleap year
         
     | 
| 
       126 
126 
     | 
    
         
             
                  31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31  // leap year
         
     | 
| 
       127 
127 
     | 
    
         
             
              };
         
     | 
| 
         @@ -215,9 +215,11 @@ struct tm *http_gmtime(const time_t *timer, struct tm *tmbuf) { 
     | 
|
| 
       215 
215 
     | 
    
         
             
              return tmbuf;
         
     | 
| 
       216 
216 
     | 
    
         
             
            }
         
     | 
| 
       217 
217 
     | 
    
         | 
| 
       218 
     | 
    
         
            -
            static char *DAY_NAMES[] = {"Sun", "Mon", "Tue", "Wed", 
     | 
| 
       219 
     | 
    
         
            -
             
     | 
| 
       220 
     | 
    
         
            -
             
     | 
| 
      
 218 
     | 
    
         
            +
            static const char *DAY_NAMES[] = {"Sun", "Mon", "Tue", "Wed",
         
     | 
| 
      
 219 
     | 
    
         
            +
                                              "Thu", "Fri", "Sat"};
         
     | 
| 
      
 220 
     | 
    
         
            +
            static const char *MONTH_NAMES[] = {"Jan ", "Feb ", "Mar ", "Apr ",
         
     | 
| 
      
 221 
     | 
    
         
            +
                                                "May ", "Jun ", "Jul ", "Aug ",
         
     | 
| 
      
 222 
     | 
    
         
            +
                                                "Sep ", "Oct ", "Nov ", "Dec "};
         
     | 
| 
       221 
223 
     | 
    
         
             
            static const char *GMT_STR = "GMT";
         
     | 
| 
       222 
224 
     | 
    
         | 
| 
       223 
225 
     | 
    
         
             
            size_t http_date2str(char *target, struct tm *tmbuf) {
         
     | 
| 
         @@ -345,6 +347,34 @@ size_t http_date2rfc2109(char *target, struct tm *tmbuf) { 
     | 
|
| 
       345 
347 
     | 
    
         
             
              return pos - target;
         
     | 
| 
       346 
348 
     | 
    
         
             
            }
         
     | 
| 
       347 
349 
     | 
    
         | 
| 
      
 350 
     | 
    
         
            +
            /**
         
     | 
| 
      
 351 
     | 
    
         
            +
             * Prints Unix time to a HTTP time formatted string.
         
     | 
| 
      
 352 
     | 
    
         
            +
             *
         
     | 
| 
      
 353 
     | 
    
         
            +
             * This variation implements chached results for faster processeing, at the
         
     | 
| 
      
 354 
     | 
    
         
            +
             * price of a less accurate string.
         
     | 
| 
      
 355 
     | 
    
         
            +
             */
         
     | 
| 
      
 356 
     | 
    
         
            +
            size_t http_time2str(char *target, const time_t t) {
         
     | 
| 
      
 357 
     | 
    
         
            +
              /* pre-print time every 1 or 2 seconds or so. */
         
     | 
| 
      
 358 
     | 
    
         
            +
              static __thread time_t cached_tick;
         
     | 
| 
      
 359 
     | 
    
         
            +
              static __thread char cached_httpdate[48];
         
     | 
| 
      
 360 
     | 
    
         
            +
              static __thread size_t chached_len;
         
     | 
| 
      
 361 
     | 
    
         
            +
              time_t last_tick = facil_last_tick();
         
     | 
| 
      
 362 
     | 
    
         
            +
              if ((t | 7) < last_tick) {
         
     | 
| 
      
 363 
     | 
    
         
            +
                /* this is a custom time, not "now", pass through */
         
     | 
| 
      
 364 
     | 
    
         
            +
                struct tm tm;
         
     | 
| 
      
 365 
     | 
    
         
            +
                http_gmtime(&t, &tm);
         
     | 
| 
      
 366 
     | 
    
         
            +
                return http_date2str(target, &tm);
         
     | 
| 
      
 367 
     | 
    
         
            +
              }
         
     | 
| 
      
 368 
     | 
    
         
            +
              if (last_tick > cached_tick) {
         
     | 
| 
      
 369 
     | 
    
         
            +
                struct tm tm;
         
     | 
| 
      
 370 
     | 
    
         
            +
                cached_tick = last_tick | 1;
         
     | 
| 
      
 371 
     | 
    
         
            +
                http_gmtime(&last_tick, &tm);
         
     | 
| 
      
 372 
     | 
    
         
            +
                chached_len = http_date2str(cached_httpdate, &tm);
         
     | 
| 
      
 373 
     | 
    
         
            +
              }
         
     | 
| 
      
 374 
     | 
    
         
            +
              memcpy(target, cached_httpdate, chached_len);
         
     | 
| 
      
 375 
     | 
    
         
            +
              return chached_len;
         
     | 
| 
      
 376 
     | 
    
         
            +
            }
         
     | 
| 
      
 377 
     | 
    
         
            +
             
     | 
| 
       348 
378 
     | 
    
         
             
            /* Credit to Jonathan Leffler for the idea of a unified conditional */
         
     | 
| 
       349 
379 
     | 
    
         
             
            #define hex_val(c)                                                             \
         
     | 
| 
       350 
380 
     | 
    
         
             
              (((c) >= '0' && (c) <= '9')                                                  \
         
     | 
    
        data/ext/iodine/http.h
    CHANGED
    
    | 
         @@ -164,6 +164,14 @@ size_t http_date2rfc2109(char *target, struct tm *tmbuf); 
     | 
|
| 
       164 
164 
     | 
    
         
             
            /** An alternative, RFC 2822 date representation. */
         
     | 
| 
       165 
165 
     | 
    
         
             
            size_t http_date2rfc2822(char *target, struct tm *tmbuf);
         
     | 
| 
       166 
166 
     | 
    
         | 
| 
      
 167 
     | 
    
         
            +
            /**
         
     | 
| 
      
 168 
     | 
    
         
            +
             * Prints Unix time to a HTTP time formatted string.
         
     | 
| 
      
 169 
     | 
    
         
            +
             *
         
     | 
| 
      
 170 
     | 
    
         
            +
             * This variation implements chached results for faster processeing, at the
         
     | 
| 
      
 171 
     | 
    
         
            +
             * price of a less accurate string.
         
     | 
| 
      
 172 
     | 
    
         
            +
             */
         
     | 
| 
      
 173 
     | 
    
         
            +
            size_t http_time2str(char *target, const time_t t);
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
       167 
175 
     | 
    
         
             
            /**
         
     | 
| 
       168 
176 
     | 
    
         
             
            A fast, inline alternative to `sprintf(dest, "%lu", num)`.
         
     | 
| 
       169 
177 
     | 
    
         | 
    
        data/ext/iodine/http1.c
    CHANGED
    
    | 
         @@ -7,34 +7,35 @@ Feel free to copy, use and enjoy according to the license provided. 
     | 
|
| 
       7 
7 
     | 
    
         
             
            #include "spnlock.inc"
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
            #include "http.h"
         
     | 
| 
       10 
     | 
    
         
            -
            #include " 
     | 
| 
      
 10 
     | 
    
         
            +
            #include "http1_parser.h"
         
     | 
| 
       11 
11 
     | 
    
         
             
            #include "http1_request.h"
         
     | 
| 
       12 
     | 
    
         
            -
            #include "http1_simple_parser.h"
         
     | 
| 
       13 
12 
     | 
    
         | 
| 
       14 
13 
     | 
    
         
             
            #include <fcntl.h>
         
     | 
| 
       15 
14 
     | 
    
         
             
            #include <stdio.h>
         
     | 
| 
       16 
15 
     | 
    
         
             
            #include <string.h>
         
     | 
| 
       17 
16 
     | 
    
         
             
            #include <sys/stat.h>
         
     | 
| 
       18 
17 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
            char * 
     | 
| 
      
 18 
     | 
    
         
            +
            char *HTTP11_Protocol_String = "facil_http/1.1_protocol";
         
     | 
| 
       20 
19 
     | 
    
         
             
            /* *****************************************************************************
         
     | 
| 
       21 
20 
     | 
    
         
             
            HTTP/1.1 data structures
         
     | 
| 
       22 
     | 
    
         
            -
            */
         
     | 
| 
      
 21 
     | 
    
         
            +
            ***************************************************************************** */
         
     | 
| 
       23 
22 
     | 
    
         | 
| 
       24 
23 
     | 
    
         
             
            typedef struct http1_protocol_s {
         
     | 
| 
       25 
24 
     | 
    
         
             
              protocol_s protocol;
         
     | 
| 
       26 
25 
     | 
    
         
             
              http_settings_s *settings;
         
     | 
| 
      
 26 
     | 
    
         
            +
              http1_parser_s parser;
         
     | 
| 
       27 
27 
     | 
    
         
             
              void (*on_request)(http_request_s *request);
         
     | 
| 
       28 
28 
     | 
    
         
             
              struct http1_protocol_s *next;
         
     | 
| 
       29 
29 
     | 
    
         
             
              http1_request_s request;
         
     | 
| 
       30 
     | 
    
         
            -
               
     | 
| 
      
 30 
     | 
    
         
            +
              size_t len;     /* used as a persistent socket `read` indication. */
         
     | 
| 
      
 31 
     | 
    
         
            +
              size_t refresh; /* a flag indicating a request callback was called. */
         
     | 
| 
       31 
32 
     | 
    
         
             
            } http1_protocol_s;
         
     | 
| 
       32 
33 
     | 
    
         | 
| 
       33 
34 
     | 
    
         
             
            static void http1_on_data(intptr_t uuid, http1_protocol_s *protocol);
         
     | 
| 
       34 
35 
     | 
    
         | 
| 
       35 
36 
     | 
    
         
             
            /* *****************************************************************************
         
     | 
| 
       36 
37 
     | 
    
         
             
            HTTP/1.1 pool
         
     | 
| 
       37 
     | 
    
         
            -
            */
         
     | 
| 
      
 38 
     | 
    
         
            +
            ***************************************************************************** */
         
     | 
| 
       38 
39 
     | 
    
         | 
| 
       39 
40 
     | 
    
         
             
            static struct {
         
     | 
| 
       40 
41 
     | 
    
         
             
              spn_lock_i lock;
         
     | 
| 
         @@ -63,7 +64,8 @@ static inline void http1_set_protocol_data(http1_protocol_s *pr) { 
     | 
|
| 
       63 
64 
     | 
    
         
             
                  .on_data = (void (*)(intptr_t, protocol_s *))http1_on_data,
         
     | 
| 
       64 
65 
     | 
    
         
             
                  .on_close = (void (*)(intptr_t uuid, protocol_s *))http1_free};
         
     | 
| 
       65 
66 
     | 
    
         
             
              pr->request.request = (http_request_s){.fd = 0, .http_version = HTTP_V1};
         
     | 
| 
       66 
     | 
    
         
            -
              pr->request.header_pos = pr->request.buffer_pos = pr->len = 0;
         
     | 
| 
      
 67 
     | 
    
         
            +
              pr->refresh = pr->request.header_pos = pr->request.buffer_pos = pr->len = 0;
         
     | 
| 
      
 68 
     | 
    
         
            +
              pr->parser = (http1_parser_s){.udata = pr};
         
     | 
| 
       67 
69 
     | 
    
         
             
            }
         
     | 
| 
       68 
70 
     | 
    
         | 
| 
       69 
71 
     | 
    
         
             
            static http1_protocol_s *http1_alloc(void) {
         
     | 
| 
         @@ -100,188 +102,295 @@ initialize: 
     | 
|
| 
       100 
102 
     | 
    
         
             
            }
         
     | 
| 
       101 
103 
     | 
    
         | 
| 
       102 
104 
     | 
    
         
             
            /* *****************************************************************************
         
     | 
| 
       103 
     | 
    
         
            -
            HTTP callbacks
         
     | 
| 
       104 
     | 
    
         
            -
            */
         
     | 
| 
       105 
     | 
    
         
            -
            #define HTTP_BODY_CHUNK_SIZE 3072 // 4096
         
     | 
| 
      
 105 
     | 
    
         
            +
            HTTP/1.1 parsre callbacks
         
     | 
| 
      
 106 
     | 
    
         
            +
            ***************************************************************************** */
         
     | 
| 
       106 
107 
     | 
    
         | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
                                              http_header_s *header) {
         
     | 
| 
       109 
     | 
    
         
            -
              ((http1_request_s *)request)
         
     | 
| 
       110 
     | 
    
         
            -
                  ->headers[((http1_request_s *)request)->header_pos] = *header;
         
     | 
| 
       111 
     | 
    
         
            -
              ((http1_request_s *)request)->header_pos += 1;
         
     | 
| 
       112 
     | 
    
         
            -
            }
         
     | 
| 
      
 108 
     | 
    
         
            +
            #define HTTP_BODY_CHUNK_SIZE 4096
         
     | 
| 
       113 
109 
     | 
    
         | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
       115 
     | 
    
         
            -
            static  
     | 
| 
       116 
     | 
    
         
            -
               
     | 
| 
       117 
     | 
    
         
            -
               
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
       119 
     | 
    
         
            -
               
     | 
| 
       120 
     | 
    
         
            -
              // handle requests with no file data
         
     | 
| 
       121 
     | 
    
         
            -
              if (request->request.body_file <= 0) {
         
     | 
| 
       122 
     | 
    
         
            -
                // request headers parsing
         
     | 
| 
       123 
     | 
    
         
            -
                if (pr->len == 0) {
         
     | 
| 
       124 
     | 
    
         
            -
                  buffer = request->buffer;
         
     | 
| 
       125 
     | 
    
         
            -
                  // make sure headers don't overflow
         
     | 
| 
       126 
     | 
    
         
            -
                  pr->len = sock_read(uuid, buffer + request->buffer_pos,
         
     | 
| 
       127 
     | 
    
         
            -
                                      HTTP1_MAX_HEADER_SIZE - request->buffer_pos);
         
     | 
| 
       128 
     | 
    
         
            -
                  // update buffer read position.
         
     | 
| 
       129 
     | 
    
         
            -
                  request->buffer_pos += pr->len;
         
     | 
| 
       130 
     | 
    
         
            -
                  // if (len > 0) {
         
     | 
| 
       131 
     | 
    
         
            -
                  //   fprintf(stderr, "\n----\nRead from socket, %lu bytes, total
         
     | 
| 
       132 
     | 
    
         
            -
                  //   %lu:\n",
         
     | 
| 
       133 
     | 
    
         
            -
                  //           len, request->buffer_pos);
         
     | 
| 
       134 
     | 
    
         
            -
                  //   for (size_t i = 0; i < request->buffer_pos; i++) {
         
     | 
| 
       135 
     | 
    
         
            -
                  //     fprintf(stderr, "%c", buffer[i] ? buffer[i] : '-');
         
     | 
| 
       136 
     | 
    
         
            -
                  //   }
         
     | 
| 
       137 
     | 
    
         
            -
                  //   fprintf(stderr, "\n");
         
     | 
| 
       138 
     | 
    
         
            -
                  // }
         
     | 
| 
       139 
     | 
    
         
            -
                }
         
     | 
| 
       140 
     | 
    
         
            -
                if (pr->len <= 0)
         
     | 
| 
       141 
     | 
    
         
            -
                  goto finished_reading;
         
     | 
| 
       142 
     | 
    
         
            -
             
     | 
| 
       143 
     | 
    
         
            -
                // parse headers
         
     | 
| 
       144 
     | 
    
         
            -
                result = http1_parse_request_headers(
         
     | 
| 
       145 
     | 
    
         
            -
                    buffer, request->buffer_pos, &request->request, http1_on_header_found);
         
     | 
| 
       146 
     | 
    
         
            -
                // review result
         
     | 
| 
       147 
     | 
    
         
            -
                if (result >= 0) { // headers comeplete
         
     | 
| 
       148 
     | 
    
         
            -
                  // are we done?
         
     | 
| 
       149 
     | 
    
         
            -
                  if (request->request.content_length == 0 || request->request.body_str) {
         
     | 
| 
       150 
     | 
    
         
            -
                    goto handle_request;
         
     | 
| 
       151 
     | 
    
         
            -
                  }
         
     | 
| 
       152 
     | 
    
         
            -
                  if (request->request.content_length > pr->settings->max_body_size) {
         
     | 
| 
       153 
     | 
    
         
            -
                    goto body_to_big;
         
     | 
| 
       154 
     | 
    
         
            -
                  }
         
     | 
| 
       155 
     | 
    
         
            -
                  // initialize or submit body data
         
     | 
| 
       156 
     | 
    
         
            -
                  result = http1_parse_request_body(buffer + result, pr->len - result,
         
     | 
| 
       157 
     | 
    
         
            -
                                                    (http_request_s *)request);
         
     | 
| 
       158 
     | 
    
         
            -
                  if (result >= 0) {
         
     | 
| 
       159 
     | 
    
         
            -
                    request->buffer_pos += result;
         
     | 
| 
       160 
     | 
    
         
            -
                    goto handle_request;
         
     | 
| 
       161 
     | 
    
         
            -
                  } else if (result == -1) // parser error
         
     | 
| 
       162 
     | 
    
         
            -
                    goto parser_error;
         
     | 
| 
       163 
     | 
    
         
            -
                  goto parse_body;
         
     | 
| 
       164 
     | 
    
         
            -
                } else if (result == -1) // parser error
         
     | 
| 
       165 
     | 
    
         
            -
                  goto parser_error;
         
     | 
| 
       166 
     | 
    
         
            -
                // assume incomplete (result == -2), even if wrong, we're right.
         
     | 
| 
       167 
     | 
    
         
            -
                pr->len = 0;
         
     | 
| 
       168 
     | 
    
         
            -
                goto postpone;
         
     | 
| 
       169 
     | 
    
         
            -
              }
         
     | 
| 
       170 
     | 
    
         
            -
              if (request->request.body_file > 0) {
         
     | 
| 
       171 
     | 
    
         
            -
              // fprintf(stderr, "Body File\n");
         
     | 
| 
       172 
     | 
    
         
            -
              parse_body:
         
     | 
| 
       173 
     | 
    
         
            -
                buffer = buff;
         
     | 
| 
       174 
     | 
    
         
            -
                // request body parsing
         
     | 
| 
       175 
     | 
    
         
            -
                pr->len = sock_read(uuid, buffer, HTTP_BODY_CHUNK_SIZE);
         
     | 
| 
       176 
     | 
    
         
            -
                if (pr->len <= 0)
         
     | 
| 
       177 
     | 
    
         
            -
                  goto finished_reading;
         
     | 
| 
       178 
     | 
    
         
            -
                result = http1_parse_request_body(buffer, pr->len, &request->request);
         
     | 
| 
       179 
     | 
    
         
            -
                if (result >= 0) {
         
     | 
| 
       180 
     | 
    
         
            -
                  goto handle_request;
         
     | 
| 
       181 
     | 
    
         
            -
                } else if (result == -1) // parser error
         
     | 
| 
       182 
     | 
    
         
            -
                  goto parser_error;
         
     | 
| 
       183 
     | 
    
         
            -
                if (pr->len < HTTP_BODY_CHUNK_SIZE) // pause parser for more data
         
     | 
| 
       184 
     | 
    
         
            -
                  goto finished_reading;
         
     | 
| 
       185 
     | 
    
         
            -
                goto parse_body;
         
     | 
| 
       186 
     | 
    
         
            -
              }
         
     | 
| 
       187 
     | 
    
         
            -
              goto postpone;
         
     | 
| 
       188 
     | 
    
         
            -
            handle_request:
         
     | 
| 
       189 
     | 
    
         
            -
              // review required headers / data
         
     | 
| 
       190 
     | 
    
         
            -
              if (request->request.host == NULL)
         
     | 
| 
      
 110 
     | 
    
         
            +
            /** called when a request was received. */
         
     | 
| 
      
 111 
     | 
    
         
            +
            static int http1_on_request(http1_parser_s *parser) {
         
     | 
| 
      
 112 
     | 
    
         
            +
              http1_protocol_s *pr = parser->udata;
         
     | 
| 
      
 113 
     | 
    
         
            +
              if (!pr)
         
     | 
| 
      
 114 
     | 
    
         
            +
                return -1;
         
     | 
| 
      
 115 
     | 
    
         
            +
              if (pr->request.request.host == NULL) {
         
     | 
| 
       191 
116 
     | 
    
         
             
                goto bad_request;
         
     | 
| 
      
 117 
     | 
    
         
            +
              }
         
     | 
| 
       192 
118 
     | 
    
         
             
              http_settings_s *settings = pr->settings;
         
     | 
| 
       193 
     | 
    
         
            -
               
     | 
| 
      
 119 
     | 
    
         
            +
              pr->request.request.settings = settings;
         
     | 
| 
       194 
120 
     | 
    
         
             
              // make sure udata to NULL, making it available for the user
         
     | 
| 
       195 
     | 
    
         
            -
               
     | 
| 
       196 
     | 
    
         
            -
              // call request callback
         
     | 
| 
       197 
     | 
    
         
            -
              if (pr  
     | 
| 
       198 
     | 
    
         
            -
                  ( 
     | 
| 
       199 
     | 
    
         
            -
             
     | 
| 
       200 
     | 
    
         
            -
             
     | 
| 
       201 
     | 
    
         
            -
             
     | 
| 
       202 
     | 
    
         
            -
             
     | 
| 
       203 
     | 
    
         
            -
                pr->on_request(&request->request);
         
     | 
| 
       204 
     | 
    
         
            -
                // fprintf(stderr, "Called on_request\n");
         
     | 
| 
      
 121 
     | 
    
         
            +
              pr->request.request.udata = NULL;
         
     | 
| 
      
 122 
     | 
    
         
            +
              // static file service or call request callback
         
     | 
| 
      
 123 
     | 
    
         
            +
              if (pr->request.request.upgrade || settings->public_folder == NULL ||
         
     | 
| 
      
 124 
     | 
    
         
            +
                  http_response_sendfile2(
         
     | 
| 
      
 125 
     | 
    
         
            +
                      NULL, &pr->request.request, settings->public_folder,
         
     | 
| 
      
 126 
     | 
    
         
            +
                      settings->public_folder_length, pr->request.request.path,
         
     | 
| 
      
 127 
     | 
    
         
            +
                      pr->request.request.path_len, settings->log_static)) {
         
     | 
| 
      
 128 
     | 
    
         
            +
                pr->on_request(&pr->request.request);
         
     | 
| 
       205 
129 
     | 
    
         
             
              }
         
     | 
| 
       206 
     | 
    
         
            -
               
     | 
| 
       207 
     | 
    
         
            -
               
     | 
| 
       208 
     | 
    
         
            -
                pr->len = 0;
         
     | 
| 
       209 
     | 
    
         
            -
                // fprintf(stderr, "\n----\nAll data consumed.\n");
         
     | 
| 
       210 
     | 
    
         
            -
              } else {
         
     | 
| 
       211 
     | 
    
         
            -
                memmove(request->buffer, buffer + result, request->buffer_pos - result);
         
     | 
| 
       212 
     | 
    
         
            -
                pr->len = request->buffer_pos - result;
         
     | 
| 
       213 
     | 
    
         
            -
                // fprintf(stderr, "\n----\ndata after move, %lu long:\n%.*s\n", len,
         
     | 
| 
       214 
     | 
    
         
            -
                //         (int)len, request->buffer);
         
     | 
| 
       215 
     | 
    
         
            -
              }
         
     | 
| 
       216 
     | 
    
         
            -
              // fprintf(stderr, "data in buffer, %lu long:\n%.*s\n", len, (int)len,
         
     | 
| 
       217 
     | 
    
         
            -
              //         request->buffer);
         
     | 
| 
       218 
     | 
    
         
            -
              // clear request state
         
     | 
| 
       219 
     | 
    
         
            -
              http1_request_clear(&request->request);
         
     | 
| 
       220 
     | 
    
         
            -
              request->buffer_pos = pr->len;
         
     | 
| 
       221 
     | 
    
         
            -
              // make sure to use the correct buffer.
         
     | 
| 
       222 
     | 
    
         
            -
              buffer = request->buffer;
         
     | 
| 
       223 
     | 
    
         
            -
            /* prevent this connection from hogging the thread by pipelining endless
         
     | 
| 
       224 
     | 
    
         
            -
             * requests.
         
     | 
| 
       225 
     | 
    
         
            -
             */
         
     | 
| 
       226 
     | 
    
         
            -
            postpone:
         
     | 
| 
       227 
     | 
    
         
            -
              facil_force_event(uuid, FIO_EVENT_ON_DATA);
         
     | 
| 
       228 
     | 
    
         
            -
              return;
         
     | 
| 
       229 
     | 
    
         
            -
            parser_error:
         
     | 
| 
       230 
     | 
    
         
            -
              if (request->request.headers_count >= HTTP1_MAX_HEADER_COUNT)
         
     | 
| 
       231 
     | 
    
         
            -
                goto too_big;
         
     | 
| 
      
 130 
     | 
    
         
            +
              pr->refresh = 1;
         
     | 
| 
      
 131 
     | 
    
         
            +
              return 0;
         
     | 
| 
       232 
132 
     | 
    
         
             
            bad_request:
         
     | 
| 
       233 
133 
     | 
    
         
             
              /* handle generally bad requests */
         
     | 
| 
       234 
134 
     | 
    
         
             
              {
         
     | 
| 
       235 
     | 
    
         
            -
                http_response_s *response = http_response_create(& 
     | 
| 
      
 135 
     | 
    
         
            +
                http_response_s *response = http_response_create(&pr->request.request);
         
     | 
| 
      
 136 
     | 
    
         
            +
                if (pr->settings->log_static)
         
     | 
| 
      
 137 
     | 
    
         
            +
                  http_response_log_start(response);
         
     | 
| 
       236 
138 
     | 
    
         
             
                response->status = 400;
         
     | 
| 
       237 
139 
     | 
    
         
             
                if (!pr->settings->public_folder ||
         
     | 
| 
       238 
     | 
    
         
            -
                    http_response_sendfile2(response, & 
     | 
| 
      
 140 
     | 
    
         
            +
                    http_response_sendfile2(response, &pr->request.request,
         
     | 
| 
       239 
141 
     | 
    
         
             
                                            pr->settings->public_folder,
         
     | 
| 
       240 
142 
     | 
    
         
             
                                            pr->settings->public_folder_length, "400.html",
         
     | 
| 
       241 
143 
     | 
    
         
             
                                            8, pr->settings->log_static)) {
         
     | 
| 
      
 144 
     | 
    
         
            +
                  response->should_close = 1;
         
     | 
| 
       242 
145 
     | 
    
         
             
                  http_response_write_body(response, "Bad Request", 11);
         
     | 
| 
       243 
146 
     | 
    
         
             
                  http_response_finish(response);
         
     | 
| 
       244 
147 
     | 
    
         
             
                }
         
     | 
| 
       245 
     | 
    
         
            -
                sock_close( 
     | 
| 
       246 
     | 
    
         
            -
                request 
     | 
| 
       247 
     | 
    
         
            -
             
     | 
| 
      
 148 
     | 
    
         
            +
                sock_close(pr->request.request.fd);
         
     | 
| 
      
 149 
     | 
    
         
            +
                pr->request.buffer_pos = 0;
         
     | 
| 
      
 150 
     | 
    
         
            +
              }
         
     | 
| 
      
 151 
     | 
    
         
            +
              return -1;
         
     | 
| 
      
 152 
     | 
    
         
            +
            }
         
     | 
| 
      
 153 
     | 
    
         
            +
            /** called when a response was received. */
         
     | 
| 
      
 154 
     | 
    
         
            +
            static int http1_on_response(http1_parser_s *parser) {
         
     | 
| 
      
 155 
     | 
    
         
            +
              return -1;
         
     | 
| 
      
 156 
     | 
    
         
            +
              (void)parser;
         
     | 
| 
      
 157 
     | 
    
         
            +
            }
         
     | 
| 
      
 158 
     | 
    
         
            +
            /** called when a request method is parsed. */
         
     | 
| 
      
 159 
     | 
    
         
            +
            static int http1_on_method(http1_parser_s *parser, char *method,
         
     | 
| 
      
 160 
     | 
    
         
            +
                                       size_t method_len) {
         
     | 
| 
      
 161 
     | 
    
         
            +
              http1_protocol_s *pr = parser->udata;
         
     | 
| 
      
 162 
     | 
    
         
            +
              if (!pr)
         
     | 
| 
      
 163 
     | 
    
         
            +
                return -1;
         
     | 
| 
      
 164 
     | 
    
         
            +
              pr->request.request.method = method;
         
     | 
| 
      
 165 
     | 
    
         
            +
              pr->request.request.method_len = method_len;
         
     | 
| 
      
 166 
     | 
    
         
            +
              return 0;
         
     | 
| 
      
 167 
     | 
    
         
            +
            }
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
            /** called when a response status is parsed. the status_str is the string
         
     | 
| 
      
 170 
     | 
    
         
            +
             * without the prefixed numerical status indicator.*/
         
     | 
| 
      
 171 
     | 
    
         
            +
            static int http1_on_status(http1_parser_s *parser, size_t status,
         
     | 
| 
      
 172 
     | 
    
         
            +
                                       char *status_str, size_t len) {
         
     | 
| 
      
 173 
     | 
    
         
            +
              return -1;
         
     | 
| 
      
 174 
     | 
    
         
            +
              (void)parser;
         
     | 
| 
      
 175 
     | 
    
         
            +
              (void)status;
         
     | 
| 
      
 176 
     | 
    
         
            +
              (void)status_str;
         
     | 
| 
      
 177 
     | 
    
         
            +
              (void)len;
         
     | 
| 
      
 178 
     | 
    
         
            +
            }
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
            /** called when a request path (excluding query) is parsed. */
         
     | 
| 
      
 181 
     | 
    
         
            +
            static int http1_on_path(http1_parser_s *parser, char *path, size_t path_len) {
         
     | 
| 
      
 182 
     | 
    
         
            +
              http1_protocol_s *pr = parser->udata;
         
     | 
| 
      
 183 
     | 
    
         
            +
              if (!pr)
         
     | 
| 
      
 184 
     | 
    
         
            +
                return -1;
         
     | 
| 
      
 185 
     | 
    
         
            +
              pr->request.request.path = path;
         
     | 
| 
      
 186 
     | 
    
         
            +
              pr->request.request.path_len = path_len;
         
     | 
| 
      
 187 
     | 
    
         
            +
              return 0;
         
     | 
| 
      
 188 
     | 
    
         
            +
            }
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
            /** called when a request path (excluding query) is parsed. */
         
     | 
| 
      
 191 
     | 
    
         
            +
            static int http1_on_query(http1_parser_s *parser, char *query,
         
     | 
| 
      
 192 
     | 
    
         
            +
                                      size_t query_len) {
         
     | 
| 
      
 193 
     | 
    
         
            +
              http1_protocol_s *pr = parser->udata;
         
     | 
| 
      
 194 
     | 
    
         
            +
              if (!pr)
         
     | 
| 
      
 195 
     | 
    
         
            +
                return -1;
         
     | 
| 
      
 196 
     | 
    
         
            +
              pr->request.request.query = query;
         
     | 
| 
      
 197 
     | 
    
         
            +
              pr->request.request.query_len = query_len;
         
     | 
| 
      
 198 
     | 
    
         
            +
              return 0;
         
     | 
| 
      
 199 
     | 
    
         
            +
            }
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
            /** called when a the HTTP/1.x version is parsed. */
         
     | 
| 
      
 202 
     | 
    
         
            +
            static int http1_on_http_version(http1_parser_s *parser, char *version,
         
     | 
| 
      
 203 
     | 
    
         
            +
                                             size_t len) {
         
     | 
| 
      
 204 
     | 
    
         
            +
              http1_protocol_s *pr = parser->udata;
         
     | 
| 
      
 205 
     | 
    
         
            +
              if (!pr)
         
     | 
| 
      
 206 
     | 
    
         
            +
                return -1;
         
     | 
| 
      
 207 
     | 
    
         
            +
              pr->request.request.version = version;
         
     | 
| 
      
 208 
     | 
    
         
            +
              pr->request.request.version_len = len;
         
     | 
| 
      
 209 
     | 
    
         
            +
              return 0;
         
     | 
| 
      
 210 
     | 
    
         
            +
            }
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
            /** called when a header is parsed. */
         
     | 
| 
      
 213 
     | 
    
         
            +
            static int http1_on_header(http1_parser_s *parser, char *name, size_t name_len,
         
     | 
| 
      
 214 
     | 
    
         
            +
                                       char *data, size_t data_len) {
         
     | 
| 
      
 215 
     | 
    
         
            +
              http1_protocol_s *pr = parser->udata;
         
     | 
| 
      
 216 
     | 
    
         
            +
              if (!pr || pr->request.header_pos >= HTTP1_MAX_HEADER_COUNT - 1)
         
     | 
| 
      
 217 
     | 
    
         
            +
                goto too_big;
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
            /** test for special headers that should be easily accessible **/
         
     | 
| 
      
 220 
     | 
    
         
            +
            #if HTTP_HEADERS_LOWERCASE
         
     | 
| 
      
 221 
     | 
    
         
            +
              if (name_len == 4 && *((uint32_t *)name) == *((uint32_t *)"host")) {
         
     | 
| 
      
 222 
     | 
    
         
            +
                pr->request.request.host = data;
         
     | 
| 
      
 223 
     | 
    
         
            +
                pr->request.request.host_len = data_len;
         
     | 
| 
      
 224 
     | 
    
         
            +
              } else if (name_len == 12 && *((uint32_t *)name) == *((uint32_t *)"cont") &&
         
     | 
| 
      
 225 
     | 
    
         
            +
                         *((uint64_t *)(name + 4)) == *((uint64_t *)"ent-type")) {
         
     | 
| 
      
 226 
     | 
    
         
            +
                pr->request.request.content_type = data;
         
     | 
| 
      
 227 
     | 
    
         
            +
                pr->request.request.content_type_len = data_len;
         
     | 
| 
      
 228 
     | 
    
         
            +
              } else if (name_len == 7 && *((uint64_t *)name) == *((uint64_t *)"upgrade")) {
         
     | 
| 
      
 229 
     | 
    
         
            +
                pr->request.request.upgrade = data;
         
     | 
| 
      
 230 
     | 
    
         
            +
                pr->request.request.upgrade_len = data_len;
         
     | 
| 
      
 231 
     | 
    
         
            +
              } else if (name_len == 10 && *((uint32_t *)name) == *((uint32_t *)"conn") &&
         
     | 
| 
      
 232 
     | 
    
         
            +
                         *((uint64_t *)(name + 2)) == *((uint64_t *)"nnection")) {
         
     | 
| 
      
 233 
     | 
    
         
            +
                pr->request.request.connection = data;
         
     | 
| 
      
 234 
     | 
    
         
            +
                pr->request.request.connection_len = data_len;
         
     | 
| 
       248 
235 
     | 
    
         
             
              }
         
     | 
| 
      
 236 
     | 
    
         
            +
            #else
         
     | 
| 
      
 237 
     | 
    
         
            +
              if (name_len == 4 && HEADER_NAME_IS_EQ(name, "host", name_len)) {
         
     | 
| 
      
 238 
     | 
    
         
            +
                pr->request.request.host = data;
         
     | 
| 
      
 239 
     | 
    
         
            +
                pr->request.request.host_len = data_len;
         
     | 
| 
      
 240 
     | 
    
         
            +
              } else if (name_len == 12 &&
         
     | 
| 
      
 241 
     | 
    
         
            +
                         HEADER_NAME_IS_EQ(name, "content-type", name_len)) {
         
     | 
| 
      
 242 
     | 
    
         
            +
                pr->request.request.content_type = data;
         
     | 
| 
      
 243 
     | 
    
         
            +
                pr->request.request.content_type_len = data_len;
         
     | 
| 
      
 244 
     | 
    
         
            +
              } else if (name_len == 7 && HEADER_NAME_IS_EQ(name, "upgrade", name_len)) {
         
     | 
| 
      
 245 
     | 
    
         
            +
                pr->request.request.upgrade = data;
         
     | 
| 
      
 246 
     | 
    
         
            +
                pr->request.request.upgrade_len = data_len;
         
     | 
| 
      
 247 
     | 
    
         
            +
              } else if (name_len == 10 &&
         
     | 
| 
      
 248 
     | 
    
         
            +
                         HEADER_NAME_IS_EQ(name, "connection", name_len)) {
         
     | 
| 
      
 249 
     | 
    
         
            +
                pr->request.request.connection = data;
         
     | 
| 
      
 250 
     | 
    
         
            +
                pr->request.request.connection_len = data_len;
         
     | 
| 
      
 251 
     | 
    
         
            +
              }
         
     | 
| 
      
 252 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 253 
     | 
    
         
            +
              pr->request.headers[pr->request.header_pos].name = name;
         
     | 
| 
      
 254 
     | 
    
         
            +
              pr->request.headers[pr->request.header_pos].name_len = name_len;
         
     | 
| 
      
 255 
     | 
    
         
            +
              pr->request.headers[pr->request.header_pos].data = data;
         
     | 
| 
      
 256 
     | 
    
         
            +
              pr->request.headers[pr->request.header_pos].data_len = data_len;
         
     | 
| 
      
 257 
     | 
    
         
            +
              pr->request.header_pos++;
         
     | 
| 
      
 258 
     | 
    
         
            +
              pr->request.request.headers_count++;
         
     | 
| 
      
 259 
     | 
    
         
            +
              return 0;
         
     | 
| 
       249 
260 
     | 
    
         
             
            too_big:
         
     | 
| 
       250 
261 
     | 
    
         
             
              /* handle oversized headers */
         
     | 
| 
       251 
262 
     | 
    
         
             
              {
         
     | 
| 
       252 
     | 
    
         
            -
                http_response_s *response = http_response_create(& 
     | 
| 
      
 263 
     | 
    
         
            +
                http_response_s *response = http_response_create(&pr->request.request);
         
     | 
| 
      
 264 
     | 
    
         
            +
                if (pr->settings->log_static)
         
     | 
| 
      
 265 
     | 
    
         
            +
                  http_response_log_start(response);
         
     | 
| 
       253 
266 
     | 
    
         
             
                response->status = 431;
         
     | 
| 
       254 
267 
     | 
    
         
             
                if (!pr->settings->public_folder ||
         
     | 
| 
       255 
     | 
    
         
            -
                    http_response_sendfile2(response, & 
     | 
| 
      
 268 
     | 
    
         
            +
                    http_response_sendfile2(response, &pr->request.request,
         
     | 
| 
       256 
269 
     | 
    
         
             
                                            pr->settings->public_folder,
         
     | 
| 
       257 
270 
     | 
    
         
             
                                            pr->settings->public_folder_length, "431.html",
         
     | 
| 
       258 
271 
     | 
    
         
             
                                            8, pr->settings->log_static)) {
         
     | 
| 
       259 
272 
     | 
    
         
             
                  http_response_write_body(response, "Request Header Fields Too Large", 31);
         
     | 
| 
       260 
273 
     | 
    
         
             
                  http_response_finish(response);
         
     | 
| 
       261 
274 
     | 
    
         
             
                }
         
     | 
| 
       262 
     | 
    
         
            -
             
     | 
| 
       263 
     | 
    
         
            -
             
     | 
| 
       264 
     | 
    
         
            -
             
     | 
| 
       265 
     | 
    
         
            -
             
     | 
| 
       266 
     | 
    
         
            -
             
     | 
| 
       267 
     | 
    
         
            -
             
     | 
| 
       268 
     | 
    
         
            -
             
     | 
| 
       269 
     | 
    
         
            -
             
     | 
| 
       270 
     | 
    
         
            -
             
     | 
| 
       271 
     | 
    
         
            -
             
     | 
| 
       272 
     | 
    
         
            -
             
     | 
| 
       273 
     | 
    
         
            -
             
     | 
| 
       274 
     | 
    
         
            -
             
     | 
| 
       275 
     | 
    
         
            -
             
     | 
| 
       276 
     | 
    
         
            -
             
     | 
| 
       277 
     | 
    
         
            -
             
     | 
| 
       278 
     | 
    
         
            -
                   
     | 
| 
       279 
     | 
    
         
            -
             
     | 
| 
       280 
     | 
    
         
            -
             
     | 
| 
      
 275 
     | 
    
         
            +
              }
         
     | 
| 
      
 276 
     | 
    
         
            +
              return -1;
         
     | 
| 
      
 277 
     | 
    
         
            +
            }
         
     | 
| 
      
 278 
     | 
    
         
            +
             
     | 
| 
      
 279 
     | 
    
         
            +
            /** called when a body chunk is parsed. */
         
     | 
| 
      
 280 
     | 
    
         
            +
            static int http1_on_body_chunk(http1_parser_s *parser, char *data,
         
     | 
| 
      
 281 
     | 
    
         
            +
                                           size_t data_len) {
         
     | 
| 
      
 282 
     | 
    
         
            +
              http1_protocol_s *pr = parser->udata;
         
     | 
| 
      
 283 
     | 
    
         
            +
              if (!pr)
         
     | 
| 
      
 284 
     | 
    
         
            +
                return -1;
         
     | 
| 
      
 285 
     | 
    
         
            +
              if (!parser->state.read) {
         
     | 
| 
      
 286 
     | 
    
         
            +
                if (parser->state.content_length > pr->settings->max_body_size)
         
     | 
| 
      
 287 
     | 
    
         
            +
                  return -1;
         
     | 
| 
      
 288 
     | 
    
         
            +
                pr->request.request.content_length = parser->state.content_length;
         
     | 
| 
      
 289 
     | 
    
         
            +
                if (pr->request.buffer_pos + parser->state.content_length <
         
     | 
| 
      
 290 
     | 
    
         
            +
                    HTTP1_MAX_HEADER_SIZE) {
         
     | 
| 
      
 291 
     | 
    
         
            +
                  pr->request.request.body_str = data;
         
     | 
| 
      
 292 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 293 
     | 
    
         
            +
            // create a temporary file to contain the data.
         
     | 
| 
      
 294 
     | 
    
         
            +
            #ifdef P_tmpdir
         
     | 
| 
      
 295 
     | 
    
         
            +
            #if defined(__linux__) /* linux doesn't end with a divider */
         
     | 
| 
      
 296 
     | 
    
         
            +
                  char template[] = P_tmpdir "/http_request_body_XXXXXXXX";
         
     | 
| 
      
 297 
     | 
    
         
            +
            #else
         
     | 
| 
      
 298 
     | 
    
         
            +
                  char template[] = P_tmpdir "http_request_body_XXXXXXXX";
         
     | 
| 
      
 299 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 300 
     | 
    
         
            +
            #else
         
     | 
| 
      
 301 
     | 
    
         
            +
                  char template[] = "/tmp/http_request_body_XXXXXXXX";
         
     | 
| 
      
 302 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 303 
     | 
    
         
            +
                  pr->request.request.body_file = mkstemp(template);
         
     | 
| 
      
 304 
     | 
    
         
            +
                  if (pr->request.request.body_file == -1)
         
     | 
| 
      
 305 
     | 
    
         
            +
                    return -1;
         
     | 
| 
       281 
306 
     | 
    
         
             
                }
         
     | 
| 
       282 
307 
     | 
    
         
             
              }
         
     | 
| 
       283 
     | 
    
         
            -
             
     | 
| 
       284 
     | 
    
         
            -
             
     | 
| 
      
 308 
     | 
    
         
            +
              if (pr->request.request.body_file) {
         
     | 
| 
      
 309 
     | 
    
         
            +
                if (write(pr->request.request.body_file, data, data_len) !=
         
     | 
| 
      
 310 
     | 
    
         
            +
                    (ssize_t)data_len)
         
     | 
| 
      
 311 
     | 
    
         
            +
                  return -1;
         
     | 
| 
      
 312 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 313 
     | 
    
         
            +
                /* nothing to do... the parser and `on_data` are doing all the work */
         
     | 
| 
      
 314 
     | 
    
         
            +
              }
         
     | 
| 
      
 315 
     | 
    
         
            +
              return 0;
         
     | 
| 
      
 316 
     | 
    
         
            +
            }
         
     | 
| 
      
 317 
     | 
    
         
            +
             
     | 
| 
      
 318 
     | 
    
         
            +
            /** called when a protocol error occured. */
         
     | 
| 
      
 319 
     | 
    
         
            +
            static int http1_on_error(http1_parser_s *parser) {
         
     | 
| 
      
 320 
     | 
    
         
            +
              http1_protocol_s *pr = parser->udata;
         
     | 
| 
      
 321 
     | 
    
         
            +
              if (!pr)
         
     | 
| 
      
 322 
     | 
    
         
            +
                return -1;
         
     | 
| 
      
 323 
     | 
    
         
            +
              sock_close(pr->request.request.fd);
         
     | 
| 
      
 324 
     | 
    
         
            +
              http1_request_clear(&pr->request.request);
         
     | 
| 
      
 325 
     | 
    
         
            +
              return 0;
         
     | 
| 
      
 326 
     | 
    
         
            +
            }
         
     | 
| 
      
 327 
     | 
    
         
            +
             
     | 
| 
      
 328 
     | 
    
         
            +
            /* *****************************************************************************
         
     | 
| 
      
 329 
     | 
    
         
            +
            HTTP/1.1 protocol callbacks
         
     | 
| 
      
 330 
     | 
    
         
            +
            ***************************************************************************** */
         
     | 
| 
      
 331 
     | 
    
         
            +
             
     | 
| 
      
 332 
     | 
    
         
            +
            /* parse and call callback */
         
     | 
| 
      
 333 
     | 
    
         
            +
            static void http1_on_data(intptr_t uuid, http1_protocol_s *pr) {
         
     | 
| 
      
 334 
     | 
    
         
            +
              size_t consumed;
         
     | 
| 
      
 335 
     | 
    
         
            +
              char buff[HTTP_BODY_CHUNK_SIZE];
         
     | 
| 
      
 336 
     | 
    
         
            +
              http1_request_s *request = &pr->request;
         
     | 
| 
      
 337 
     | 
    
         
            +
              char *buffer = request->buffer;
         
     | 
| 
      
 338 
     | 
    
         
            +
              ssize_t tmp = 0;
         
     | 
| 
      
 339 
     | 
    
         
            +
              // handle requests with no file data
         
     | 
| 
      
 340 
     | 
    
         
            +
              if (request->request.body_file <= 0) {
         
     | 
| 
      
 341 
     | 
    
         
            +
                // read into the request buffer.
         
     | 
| 
      
 342 
     | 
    
         
            +
                tmp = sock_read(uuid, request->buffer + request->buffer_pos,
         
     | 
| 
      
 343 
     | 
    
         
            +
                                HTTP1_MAX_HEADER_SIZE - request->buffer_pos);
         
     | 
| 
      
 344 
     | 
    
         
            +
                if (tmp > 0) {
         
     | 
| 
      
 345 
     | 
    
         
            +
                  request->buffer_pos += tmp;
         
     | 
| 
      
 346 
     | 
    
         
            +
                  pr->len += tmp;
         
     | 
| 
      
 347 
     | 
    
         
            +
                } else
         
     | 
| 
      
 348 
     | 
    
         
            +
                  tmp = 0;
         
     | 
| 
      
 349 
     | 
    
         
            +
                buffer = request->buffer + request->buffer_pos - pr->len;
         
     | 
| 
      
 350 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 351 
     | 
    
         
            +
                buffer = buff;
         
     | 
| 
      
 352 
     | 
    
         
            +
                tmp = sock_read(uuid, buffer, HTTP_BODY_CHUNK_SIZE);
         
     | 
| 
      
 353 
     | 
    
         
            +
                if (tmp > 0) {
         
     | 
| 
      
 354 
     | 
    
         
            +
                  request->buffer_pos += tmp;
         
     | 
| 
      
 355 
     | 
    
         
            +
                  pr->len += tmp;
         
     | 
| 
      
 356 
     | 
    
         
            +
                } else
         
     | 
| 
      
 357 
     | 
    
         
            +
                  tmp = 0;
         
     | 
| 
      
 358 
     | 
    
         
            +
              }
         
     | 
| 
      
 359 
     | 
    
         
            +
             
     | 
| 
      
 360 
     | 
    
         
            +
              if (pr->len == 0)
         
     | 
| 
      
 361 
     | 
    
         
            +
                return;
         
     | 
| 
      
 362 
     | 
    
         
            +
             
     | 
| 
      
 363 
     | 
    
         
            +
              // parse HTTP data
         
     | 
| 
      
 364 
     | 
    
         
            +
              consumed =
         
     | 
| 
      
 365 
     | 
    
         
            +
                  http1_fio_parser(.parser = &pr->parser, .buffer = buffer,
         
     | 
| 
      
 366 
     | 
    
         
            +
                                   .length = pr->len, .on_request = http1_on_request,
         
     | 
| 
      
 367 
     | 
    
         
            +
                                   .on_response = http1_on_response,
         
     | 
| 
      
 368 
     | 
    
         
            +
                                   .on_method = http1_on_method,
         
     | 
| 
      
 369 
     | 
    
         
            +
                                   .on_status = http1_on_status, .on_path = http1_on_path,
         
     | 
| 
      
 370 
     | 
    
         
            +
                                   .on_query = http1_on_query,
         
     | 
| 
      
 371 
     | 
    
         
            +
                                   .on_http_version = http1_on_http_version,
         
     | 
| 
      
 372 
     | 
    
         
            +
                                   .on_header = http1_on_header,
         
     | 
| 
      
 373 
     | 
    
         
            +
                                   .on_body_chunk = http1_on_body_chunk,
         
     | 
| 
      
 374 
     | 
    
         
            +
                                   .on_error = http1_on_error);
         
     | 
| 
      
 375 
     | 
    
         
            +
             
     | 
| 
      
 376 
     | 
    
         
            +
              // handle leftovers, if any
         
     | 
| 
      
 377 
     | 
    
         
            +
              if (pr->refresh) {
         
     | 
| 
      
 378 
     | 
    
         
            +
                pr->refresh = 0;
         
     | 
| 
      
 379 
     | 
    
         
            +
                if (pr->len > consumed) {
         
     | 
| 
      
 380 
     | 
    
         
            +
                  memmove(request->buffer, buffer + consumed, pr->len - consumed);
         
     | 
| 
      
 381 
     | 
    
         
            +
                  pr->len = pr->len - consumed;
         
     | 
| 
      
 382 
     | 
    
         
            +
                  http1_request_clear(&request->request);
         
     | 
| 
      
 383 
     | 
    
         
            +
                  request->buffer_pos = pr->len;
         
     | 
| 
      
 384 
     | 
    
         
            +
                  facil_force_event(uuid, FIO_EVENT_ON_DATA);
         
     | 
| 
      
 385 
     | 
    
         
            +
                  return;
         
     | 
| 
      
 386 
     | 
    
         
            +
                }
         
     | 
| 
      
 387 
     | 
    
         
            +
                http1_request_clear(&request->request);
         
     | 
| 
      
 388 
     | 
    
         
            +
                pr->len = 0;
         
     | 
| 
      
 389 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 390 
     | 
    
         
            +
                pr->len = pr->len - consumed;
         
     | 
| 
      
 391 
     | 
    
         
            +
              }
         
     | 
| 
      
 392 
     | 
    
         
            +
              if (tmp)
         
     | 
| 
      
 393 
     | 
    
         
            +
                facil_force_event(uuid, FIO_EVENT_ON_DATA);
         
     | 
| 
       285 
394 
     | 
    
         
             
            }
         
     | 
| 
       286 
395 
     | 
    
         | 
| 
       287 
396 
     | 
    
         
             
            /* *****************************************************************************
         
     | 
| 
         @@ -353,8 +462,8 @@ is_busy: 
     | 
|
| 
       353 
462 
     | 
    
         | 
| 
       354 
463 
     | 
    
         
             
            busy_no_file:
         
     | 
| 
       355 
464 
     | 
    
         
             
              sock_write(fd,
         
     | 
| 
       356 
     | 
    
         
            -
                         "HTTP/1.1 503 Service Unavailable\r\ 
     | 
| 
       357 
     | 
    
         
            -
                         "13\r\n\r\nServer Busy.",
         
     | 
| 
      
 465 
     | 
    
         
            +
                         "HTTP/1.1 503 Service Unavailable\r\n"
         
     | 
| 
      
 466 
     | 
    
         
            +
                         "Content-Length: 13\r\n\r\nServer Busy.",
         
     | 
| 
       358 
467 
     | 
    
         
             
                         68);
         
     | 
| 
       359 
468 
     | 
    
         
             
              sock_close(fd);
         
     | 
| 
       360 
469 
     | 
    
         
             
              return NULL;
         
     |