LCOV - code coverage report
Current view: top level - libcli/http - http.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 263 429 61.3 %
Date: 2021-08-25 13:27:56 Functions: 20 23 87.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    HTTP library
       5             : 
       6             :    Copyright (C) 2013 Samuel Cabrero <samuelcabrero@kernevil.me>
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "lib/util/tevent_ntstatus.h"
      24             : #include "http.h"
      25             : #include "http_internal.h"
      26             : #include "util/tevent_werror.h"
      27             : #include "lib/util/dlinklist.h"
      28             : 
      29             : #undef strcasecmp
      30             : 
      31             : /**
      32             :  * Determines if a response should have a body.
      33             :  * @return 1 if the response MUST have a body; 0 if the response MUST NOT have
      34             :  *     a body. Returns -1 on error.
      35             :  */
      36           6 : static int http_response_needs_body(struct http_request *req)
      37             : {
      38           6 :         struct http_header *h = NULL;
      39             : 
      40           6 :         if (!req) return -1;
      41             : 
      42          48 :         for (h = req->headers; h != NULL; h = h->next) {
      43             :                 int cmp;
      44             :                 int n;
      45             :                 char c;
      46             :                 unsigned long long v;
      47             : 
      48          24 :                 cmp = strcasecmp(h->key, "Content-Length");
      49          24 :                 if (cmp != 0) {
      50          18 :                         continue;
      51             :                 }
      52             : 
      53           6 :                 n = sscanf(h->value, "%llu%c", &v, &c);
      54           6 :                 if (n != 1) {
      55           6 :                         return -1;
      56             :                 }
      57             : 
      58           6 :                 req->remaining_content_length = v;
      59             : 
      60           6 :                 if (v != 0) {
      61           6 :                         return 1;
      62             :                 }
      63             : 
      64           0 :                 return 0;
      65             :         }
      66             : 
      67           0 :         return 0;
      68             : }
      69             : 
      70             : struct http_read_response_state {
      71             :         enum http_parser_state  parser_state;
      72             :         size_t                  max_headers_size;
      73             :         uint64_t                max_content_length;
      74             :         DATA_BLOB               buffer;
      75             :         struct http_request     *response;
      76             : };
      77             : 
      78             : /**
      79             :  * Parses the HTTP headers
      80             :  */
      81         854 : static enum http_read_status http_parse_headers(struct http_read_response_state *state)
      82             : {
      83         854 :         enum http_read_status   status = HTTP_ALL_DATA_READ;
      84         854 :         char                    *ptr = NULL;
      85         854 :         char                    *line = NULL;
      86         854 :         char                    *key = NULL;
      87         854 :         char                    *value = NULL;
      88         854 :         int                     n = 0;
      89             :         int                     ret;
      90             : 
      91             :         /* Sanity checks */
      92         854 :         if (!state || !state->response) {
      93           0 :                 DEBUG(0, ("%s: Invalid Parameter\n", __func__));
      94           0 :                 return HTTP_DATA_CORRUPTED;
      95             :         }
      96             : 
      97         854 :         if (state->buffer.length > state->max_headers_size) {
      98           0 :                 DEBUG(0, ("%s: Headers too long: %zi, maximum length is %zi\n", __func__,
      99             :                           state->buffer.length, state->max_headers_size));
     100           0 :                 return HTTP_DATA_TOO_LONG;
     101             :         }
     102             : 
     103         854 :         line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
     104         854 :         if (!line) {
     105           0 :                 DEBUG(0, ("%s: Memory error\n", __func__));
     106           0 :                 return HTTP_DATA_CORRUPTED;
     107             :         }
     108             : 
     109         854 :         ptr = strstr(line, "\r\n");
     110         854 :         if (ptr == NULL) {
     111         824 :                 TALLOC_FREE(line);
     112         824 :                 return HTTP_MORE_DATA_EXPECTED;
     113             :         }
     114             : 
     115          30 :         state->response->headers_size += state->buffer.length;
     116             : 
     117          30 :         if (strncmp(line, "\r\n", 2) == 0) {
     118           6 :                 DEBUG(11,("%s: All headers read\n", __func__));
     119             : 
     120           6 :                 ret = http_response_needs_body(state->response);
     121           6 :                 switch (ret) {
     122           6 :                 case 1:
     123           6 :                         if (state->response->remaining_content_length <= state->max_content_length) {
     124           6 :                                 DEBUG(11, ("%s: Start of read body\n", __func__));
     125           6 :                                 state->parser_state = HTTP_READING_BODY;
     126           6 :                                 break;
     127             :                         }
     128             :                         FALL_THROUGH;
     129             :                 case 0:
     130           0 :                         DEBUG(11, ("%s: Skipping body for code %d\n", __func__,
     131             :                                    state->response->response_code));
     132           0 :                         state->parser_state = HTTP_READING_DONE;
     133           0 :                         break;
     134           0 :                 case -1:
     135           0 :                         DEBUG(0, ("%s_: Error in http_response_needs_body\n", __func__));
     136           0 :                         TALLOC_FREE(line);
     137           0 :                         return HTTP_DATA_CORRUPTED;
     138             :                         break;
     139             :                 }
     140             : 
     141           6 :                 TALLOC_FREE(line);
     142           6 :                 return HTTP_ALL_DATA_READ;
     143             :         }
     144             : 
     145          24 :         n = sscanf(line, "%m[^:]: %m[^\r\n]\r\n", &key, &value);
     146          24 :         if (n != 2) {
     147           0 :                 DEBUG(0, ("%s: Error parsing header '%s'\n", __func__, line));
     148           0 :                 status = HTTP_DATA_CORRUPTED;
     149           0 :                 goto error;
     150             :         }
     151             : 
     152          24 :         if (http_add_header(state->response, &state->response->headers, key, value) == -1) {
     153           0 :                 DEBUG(0, ("%s: Error adding header\n", __func__));
     154           0 :                 status = HTTP_DATA_CORRUPTED;
     155           0 :                 goto error;
     156             :         }
     157             : 
     158          48 : error:
     159          24 :         free(key);
     160          24 :         free(value);
     161          24 :         TALLOC_FREE(line);
     162          24 :         return status;
     163             : }
     164             : 
     165             : /**
     166             :  * Parses the first line of a HTTP response
     167             :  */
     168           6 : static bool http_parse_response_line(struct http_read_response_state *state)
     169             : {
     170           6 :         bool    status = true;
     171             :         char    *protocol;
     172           6 :         char    *msg = NULL;
     173             :         char    major;
     174             :         char    minor;
     175             :         int     code;
     176           6 :         char    *line = NULL;
     177             :         int     n;
     178             : 
     179             :         /* Sanity checks */
     180           6 :         if (!state) {
     181           0 :                 DEBUG(0, ("%s: Input parameter is NULL\n", __func__));
     182           0 :                 return false;
     183             :         }
     184             : 
     185           6 :         line = talloc_strndup(state, (char*)state->buffer.data, state->buffer.length);
     186           6 :         if (!line) {
     187           0 :                 DEBUG(0, ("%s: Memory error\n", __func__));
     188           0 :                 return false;
     189             :         }
     190             : 
     191           6 :         n = sscanf(line, "%m[^/]/%c.%c %d %m[^\r\n]\r\n",
     192             :                    &protocol, &major, &minor, &code, &msg);
     193             : 
     194           6 :         DEBUG(11, ("%s: Header parsed(%i): protocol->%s, major->%c, minor->%c, "
     195             :                    "code->%d, message->%s\n", __func__, n, protocol, major, minor,
     196             :                    code, msg));
     197             : 
     198           6 :         if (n != 5) {
     199           0 :                 DEBUG(0, ("%s: Error parsing header\n",       __func__));
     200           0 :                 status = false;
     201           0 :                 goto error;
     202             :         }
     203             : 
     204           6 :         if (major != '1') {
     205           0 :                 DEBUG(0, ("%s: Bad HTTP major number '%c'\n", __func__, major));
     206           0 :                 status = false;
     207           0 :                 goto error;
     208             :         }
     209             : 
     210           6 :         if (code == 0) {
     211           0 :                 DEBUG(0, ("%s: Bad response code '%d'", __func__, code));
     212           0 :                 status = false;
     213           0 :                 goto error;
     214             :         }
     215             : 
     216           6 :         if (msg == NULL) {
     217           0 :                 DEBUG(0, ("%s: Error parsing HTTP data\n", __func__));
     218           0 :                 status = false;
     219           0 :                 goto error;
     220             :         }
     221             : 
     222           6 :         state->response->major = major;
     223           6 :         state->response->minor = minor;
     224           6 :         state->response->response_code = code;
     225           6 :         state->response->response_code_line = talloc_strndup(state->response,
     226             :                                                              msg, strlen(msg));
     227             : 
     228           6 : error:
     229           6 :         free(protocol);
     230           6 :         free(msg);
     231           6 :         TALLOC_FREE(line);
     232           6 :         return status;
     233             : }
     234             : 
     235             : /*
     236             :  * Parses header lines from a request or a response into the specified
     237             :  * request object given a buffer.
     238             :  *
     239             :  * Returns
     240             :  *   HTTP_DATA_CORRUPTED                on error
     241             :  *   HTTP_MORE_DATA_EXPECTED    when we need to read more headers
     242             :  *   HTTP_DATA_TOO_LONG                 on error
     243             :  *   HTTP_ALL_DATA_READ                 when all headers have been read
     244             :  */
     245         102 : static enum http_read_status http_parse_firstline(struct http_read_response_state *state)
     246             : {
     247         102 :         enum http_read_status   status = HTTP_ALL_DATA_READ;
     248         102 :         char                    *ptr = NULL;
     249             :         char                    *line;
     250             : 
     251             :         /* Sanity checks */
     252         102 :         if (!state) {
     253           0 :                 DEBUG(0, ("%s: Invalid Parameter\n", __func__));
     254           0 :                 return HTTP_DATA_CORRUPTED;
     255             :         }
     256             : 
     257         102 :         if (state->buffer.length > state->max_headers_size) {
     258           0 :                 DEBUG(0, ("%s: Headers too long: %zi, maximum length is %zi\n", __func__,
     259             :                           state->buffer.length, state->max_headers_size));
     260           0 :                 return HTTP_DATA_TOO_LONG;
     261             :         }
     262             : 
     263         102 :         line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
     264         102 :         if (!line) {
     265           0 :                 DEBUG(0, ("%s: Not enough memory\n", __func__));
     266           0 :                 return HTTP_DATA_CORRUPTED;
     267             :         }
     268             : 
     269         102 :         ptr = strstr(line, "\r\n");
     270         102 :         if (ptr == NULL) {
     271          96 :                 TALLOC_FREE(line);
     272          96 :                 return HTTP_MORE_DATA_EXPECTED;
     273             :         }
     274             : 
     275           6 :         state->response->headers_size = state->buffer.length;
     276           6 :         if (!http_parse_response_line(state)) {
     277           0 :                 status = HTTP_DATA_CORRUPTED;
     278             :         }
     279             : 
     280             :         /* Next state, read HTTP headers */
     281           6 :         state->parser_state = HTTP_READING_HEADERS;
     282             : 
     283           6 :         TALLOC_FREE(line);
     284           6 :         return status;
     285             : }
     286             : 
     287        3765 : static enum http_read_status http_read_body(struct http_read_response_state *state)
     288             : {
     289        3765 :         struct http_request *resp = state->response;
     290             : 
     291        3765 :         if (state->buffer.length < resp->remaining_content_length) {
     292        3759 :                 return HTTP_MORE_DATA_EXPECTED;
     293             :         }
     294             : 
     295           6 :         resp->body = state->buffer;
     296           6 :         state->buffer = data_blob_null;
     297           6 :         talloc_steal(resp, resp->body.data);
     298           6 :         resp->remaining_content_length = 0;
     299             : 
     300           6 :         state->parser_state = HTTP_READING_DONE;
     301           6 :         return HTTP_ALL_DATA_READ;
     302             : }
     303             : 
     304           0 : static enum http_read_status http_read_trailer(struct http_read_response_state *state)
     305             : {
     306           0 :         enum http_read_status status = HTTP_DATA_CORRUPTED;
     307             :         /* TODO */
     308           0 :         return status;
     309             : }
     310             : 
     311        4721 : static enum http_read_status http_parse_buffer(struct http_read_response_state *state)
     312             : {
     313        4721 :         if (!state) {
     314           0 :                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
     315           0 :                 return HTTP_DATA_CORRUPTED;
     316             :         }
     317             : 
     318        4721 :         switch (state->parser_state) {
     319         102 :                 case HTTP_READING_FIRSTLINE:
     320         102 :                         return http_parse_firstline(state);
     321         854 :                 case HTTP_READING_HEADERS:
     322         854 :                         return http_parse_headers(state);
     323        3765 :                 case HTTP_READING_BODY:
     324        3765 :                         return http_read_body(state);
     325             :                         break;
     326           0 :                 case HTTP_READING_TRAILER:
     327           0 :                         return http_read_trailer(state);
     328             :                         break;
     329           0 :                 case HTTP_READING_DONE:
     330             :                         /* All read */
     331           0 :                         return HTTP_ALL_DATA_READ;
     332           0 :                 default:
     333           0 :                         DEBUG(0, ("%s: Illegal parser state %d", __func__,
     334             :                                   state->parser_state));
     335           0 :                         break;
     336             :         }
     337           0 :         return HTTP_DATA_CORRUPTED;
     338             : }
     339             : 
     340          54 : static int http_header_is_valid_value(const char *value)
     341             : {
     342          54 :         const char      *p = NULL;
     343             : 
     344             :         /* Sanity checks */
     345          54 :         if (!value) {
     346           0 :                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
     347           0 :                 return -1;
     348             :         }
     349          54 :         p = value;
     350             : 
     351         108 :         while ((p = strpbrk(p, "\r\n")) != NULL) {
     352             :                 /* Expect only one new line */
     353           0 :                 p += strspn(p, "\r\n");
     354             :                 /* Expect a space or tab for continuation */
     355           0 :                 if (*p != ' ' && *p != '\t')
     356           0 :                         return (0);
     357             :         }
     358          54 :         return 1;
     359             : }
     360             : 
     361          54 : static int http_add_header_internal(TALLOC_CTX *mem_ctx,
     362             :                                     struct http_header **headers,
     363             :                                     const char *key, const char *value,
     364             :                                     bool replace)
     365             : {
     366          54 :         struct http_header *tail = NULL;
     367          54 :         struct http_header *h = NULL;
     368             : 
     369             :         /* Sanity checks */
     370          54 :         if (!headers || !key || !value) {
     371           0 :                 DEBUG(0, ("Invalid parameter\n"));
     372           0 :                 return -1;
     373             :         }
     374             : 
     375             : 
     376             : 
     377          54 :         if (replace) {
     378           0 :                 for (h = *headers; h != NULL; h = h->next) {
     379           0 :                         if (strcasecmp(key, h->key) == 0) {
     380           0 :                                 break;
     381             :                         }
     382             :                 }
     383             : 
     384           0 :                 if (h != NULL) {
     385             :                         /* Replace header value */
     386           0 :                         if (h->value) {
     387           0 :                                 talloc_free(h->value);
     388             :                         }
     389           0 :                         h->value = talloc_strdup(h, value);
     390           0 :                         DEBUG(11, ("%s: Replaced HTTP header: key '%s', value '%s'\n",
     391             :                                         __func__, h->key, h->value));
     392           0 :                         return 0;
     393             :                 }
     394             :         }
     395             : 
     396             :         /* Add new header */
     397          54 :         h = talloc(mem_ctx, struct http_header);
     398          54 :         h->key = talloc_strdup(h, key);
     399          54 :         h->value = talloc_strdup(h, value);
     400          54 :         DLIST_ADD_END(*headers, h);
     401          54 :         tail = DLIST_TAIL(*headers);
     402          54 :         if (tail != h) {
     403           0 :                 DEBUG(0, ("%s: Error adding header\n", __func__));
     404           0 :                 return -1;
     405             :         }
     406          54 :         DEBUG(11, ("%s: Added HTTP header: key '%s', value '%s'\n",
     407             :                         __func__, h->key, h->value));
     408          54 :         return 0;
     409             : }
     410             : 
     411          54 : int http_add_header(TALLOC_CTX *mem_ctx,
     412             :                     struct http_header **headers,
     413             :                     const char *key, const char *value)
     414             : {
     415          54 :         if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
     416           0 :                 DEBUG(0, ("%s: Dropping illegal header key\n", __func__));
     417           0 :                 return -1;
     418             :         }
     419             : 
     420          54 :         if (!http_header_is_valid_value(value)) {
     421           0 :                 DEBUG(0, ("%s: Dropping illegal header value\n", __func__));
     422           0 :                 return -1;
     423             :         }
     424             : 
     425          54 :         return (http_add_header_internal(mem_ctx, headers, key, value, false));
     426             : }
     427             : 
     428           0 : int http_replace_header(TALLOC_CTX *mem_ctx,
     429             :                     struct http_header **headers,
     430             :                     const char *key, const char *value)
     431             : {
     432           0 :         if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
     433           0 :                 DEBUG(0, ("%s: Dropping illegal header key\n", __func__));
     434           0 :                 return -1;
     435             :         }
     436             : 
     437           0 :         if (!http_header_is_valid_value(value)) {
     438           0 :                 DEBUG(0, ("%s: Dropping illegal header value\n", __func__));
     439           0 :                 return -1;
     440             :         }
     441             : 
     442           0 :         return (http_add_header_internal(mem_ctx, headers, key, value, true));
     443             : }
     444             : 
     445             : /**
     446             :  * Remove a header from the headers list.
     447             :  *
     448             :  * Returns 0,  if the header was successfully removed.
     449             :  * Returns -1, if the header could not be found.
     450             :  */
     451           0 : int http_remove_header(struct http_header **headers, const char *key)
     452             : {
     453             :         struct http_header *header;
     454             : 
     455             :         /* Sanity checks */
     456           0 :         if (!headers || !key) {
     457           0 :                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
     458           0 :                 return -1;
     459             :         }
     460             : 
     461           0 :         for(header = *headers; header != NULL; header = header->next) {
     462           0 :                 if (strcmp(key, header->key) == 0) {
     463           0 :                         DLIST_REMOVE(*headers, header);
     464           0 :                         return 0;
     465             :                 }
     466             :         }
     467           0 :         return -1;
     468             : }
     469             : 
     470        4727 : static int http_read_response_next_vector(struct tstream_context *stream,
     471             :                                           void *private_data,
     472             :                                           TALLOC_CTX *mem_ctx,
     473             :                                           struct iovec **_vector,
     474             :                                           size_t *_count)
     475             : {
     476             :         struct http_read_response_state *state;
     477             :         struct iovec                    *vector;
     478             : 
     479             :         /* Sanity checks */
     480        4727 :         if (!stream || !private_data || !_vector || !_count) {
     481           0 :                 DEBUG(0, ("%s: Invalid Parameter\n", __func__));
     482           0 :                 return -1;
     483             :         }
     484             : 
     485        4727 :         state = talloc_get_type_abort(private_data, struct http_read_response_state);
     486        4727 :         vector = talloc_array(mem_ctx, struct iovec, 1);
     487        4727 :         if (!vector) {
     488           0 :                 DEBUG(0, ("%s: No more memory\n", __func__));
     489           0 :                 return -1;
     490             :         }
     491             : 
     492        4727 :         if (state->buffer.data == NULL) {
     493             :                 /* Allocate buffer */
     494           6 :                 state->buffer.data = talloc_zero_array(state, uint8_t, 1);
     495           6 :                 if (!state->buffer.data) {
     496           0 :                         DEBUG(0, ("%s: No more memory\n", __func__));
     497           0 :                         return -1;
     498             :                 }
     499           6 :                 state->buffer.length = 1;
     500             : 
     501             :                 /* Return now, nothing to parse yet */
     502           6 :                 vector[0].iov_base = (void *)(state->buffer.data);
     503           6 :                 vector[0].iov_len = 1;
     504           6 :                 *_vector = vector;
     505           6 :                 *_count = 1;
     506           6 :                 return 0;
     507             :         }
     508             : 
     509        4721 :         switch (http_parse_buffer(state)) {
     510          42 :                 case HTTP_ALL_DATA_READ:
     511          42 :                         if (state->parser_state == HTTP_READING_DONE) {
     512             :                                 /* Full request or response parsed */
     513           6 :                                 *_vector = NULL;
     514           6 :                                 *_count = 0;
     515             :                         } else {
     516             :                                 /* Free current buffer and allocate new one */
     517          36 :                                 TALLOC_FREE(state->buffer.data);
     518          36 :                                 state->buffer.data = talloc_zero_array(state, uint8_t, 1);
     519          36 :                                 if (!state->buffer.data) {
     520           0 :                                         return -1;
     521             :                                 }
     522          36 :                                 state->buffer.length = 1;
     523             : 
     524          36 :                                 vector[0].iov_base = (void *)(state->buffer.data);
     525          36 :                                 vector[0].iov_len = 1;
     526          36 :                                 *_vector = vector;
     527          36 :                                 *_count = 1;
     528             :                         }
     529          42 :                         break;
     530        4679 :                 case HTTP_MORE_DATA_EXPECTED:
     531             :                         /* TODO Optimize, allocating byte by byte */
     532        4679 :                         state->buffer.data = talloc_realloc(state, state->buffer.data,
     533             :                                                             uint8_t, state->buffer.length + 1);
     534        4679 :                         if (!state->buffer.data) {
     535           0 :                                 return -1;
     536             :                         }
     537        4679 :                         state->buffer.length++;
     538        9358 :                         vector[0].iov_base = (void *)(state->buffer.data +
     539        4679 :                                                       state->buffer.length - 1);
     540        4679 :                         vector[0].iov_len = 1;
     541        4679 :                         *_vector = vector;
     542        4679 :                         *_count = 1;
     543        4679 :                         break;
     544           0 :                 case HTTP_DATA_CORRUPTED:
     545             :                 case HTTP_REQUEST_CANCELED:
     546             :                 case HTTP_DATA_TOO_LONG:
     547           0 :                         return -1;
     548             :                         break;
     549           0 :                 default:
     550           0 :                         DEBUG(0, ("%s: Unexpected status\n", __func__));
     551           0 :                         break;
     552             :         }
     553        4721 :         return 0;
     554             : }
     555             : 
     556             : 
     557             : /**
     558             :  * Reads a HTTP response
     559             :  */
     560             : static void http_read_response_done(struct tevent_req *);
     561           6 : struct tevent_req *http_read_response_send(TALLOC_CTX *mem_ctx,
     562             :                                            struct tevent_context *ev,
     563             :                                            struct http_conn *http_conn,
     564             :                                            size_t max_content_length)
     565             : {
     566             :         struct tevent_req               *req;
     567             :         struct tevent_req               *subreq;
     568             :         struct http_read_response_state *state;
     569             : 
     570           6 :         DEBUG(11, ("%s: Reading HTTP response\n", __func__));
     571             : 
     572             :         /* Sanity checks */
     573           6 :         if (ev == NULL || http_conn == NULL) {
     574           0 :                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
     575           0 :                 return NULL;
     576             :         }
     577             : 
     578           6 :         req = tevent_req_create(mem_ctx, &state, struct http_read_response_state);
     579           6 :         if (req == NULL) {
     580           0 :                 return NULL;
     581             :         }
     582             : 
     583           6 :         state->max_headers_size = HTTP_MAX_HEADER_SIZE;
     584           6 :         state->max_content_length = (uint64_t)max_content_length;
     585           6 :         state->parser_state = HTTP_READING_FIRSTLINE;
     586           6 :         state->response = talloc_zero(state, struct http_request);
     587           6 :         if (tevent_req_nomem(state->response, req)) {
     588           0 :                 return tevent_req_post(req, ev);
     589             :         }
     590             : 
     591           6 :         subreq = tstream_readv_pdu_send(state, ev, http_conn->tstreams.active,
     592             :                                         http_read_response_next_vector,
     593             :                                         state);
     594           6 :         if (tevent_req_nomem(subreq,req)) {
     595           0 :                 return tevent_req_post(req, ev);
     596             :         }
     597           6 :         tevent_req_set_callback(subreq, http_read_response_done, req);
     598             : 
     599           6 :         return req;
     600             : }
     601             : 
     602           6 : static void http_read_response_done(struct tevent_req *subreq)
     603             : {
     604             :         NTSTATUS                        status;
     605             :         struct tevent_req               *req;
     606             :         int                             ret;
     607             :         int                             sys_errno;
     608             : 
     609           6 :         if (!subreq) {
     610           0 :                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
     611           0 :                 return;
     612             :         }
     613             : 
     614           6 :         req = tevent_req_callback_data(subreq, struct tevent_req);
     615             : 
     616           6 :         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
     617           6 :         DEBUG(11, ("%s: HTTP response read (%d bytes)\n", __func__, ret));
     618           6 :         TALLOC_FREE(subreq);
     619           6 :         if (ret == -1) {
     620           0 :                 status = map_nt_error_from_unix_common(sys_errno);
     621           0 :                 DEBUG(0, ("%s: Failed to read HTTP response: %s\n",
     622             :                           __func__, nt_errstr(status)));
     623           0 :                 tevent_req_nterror(req, status);
     624           0 :                 return;
     625             :         }
     626             : 
     627           6 :         tevent_req_done(req);
     628             : }
     629             : 
     630           6 : NTSTATUS http_read_response_recv(struct tevent_req *req,
     631             :                                  TALLOC_CTX *mem_ctx,
     632             :                                  struct http_request **response)
     633             : {
     634             :         NTSTATUS status;
     635             :         struct http_read_response_state *state;
     636             : 
     637           6 :         if (!mem_ctx || !response || !req) {
     638           0 :                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
     639           0 :                 return NT_STATUS_INVALID_PARAMETER;
     640             :         }
     641           6 :         if (tevent_req_is_nterror(req, &status)) {
     642           0 :                 tevent_req_received(req);
     643           0 :                 return status;
     644             :         }
     645             : 
     646           6 :         state = tevent_req_data(req, struct http_read_response_state);
     647           6 :         *response = state->response;
     648           6 :         talloc_steal(mem_ctx, state->response);
     649             : 
     650           6 :         tevent_req_received(req);
     651             : 
     652           6 :         return NT_STATUS_OK;
     653             : }
     654             : 
     655           6 : static const char *http_method_str(enum http_cmd_type type)
     656             : {
     657             :         const char *method;
     658             : 
     659           6 :         switch (type) {
     660           6 :         case HTTP_REQ_POST:
     661           6 :                 method = "POST";
     662           6 :                 break;
     663           0 :         case HTTP_REQ_RPC_IN_DATA:
     664           0 :                 method = "RPC_IN_DATA";
     665           0 :                 break;
     666           0 :         case HTTP_REQ_RPC_OUT_DATA:
     667           0 :                 method = "RPC_OUT_DATA";
     668           0 :                 break;
     669           0 :         default:
     670           0 :                 method = NULL;
     671           0 :                 break;
     672             :         }
     673             : 
     674           6 :         return method;
     675             : }
     676             : 
     677           6 : static NTSTATUS http_push_request_line(TALLOC_CTX *mem_ctx,
     678             :                                        DATA_BLOB *buffer,
     679             :                                        const struct http_request *req)
     680             : {
     681             :         const char      *method;
     682             :         char            *str;
     683             : 
     684             :         /* Sanity checks */
     685           6 :         if (!buffer || !req) {
     686           0 :                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
     687           0 :                 return NT_STATUS_INVALID_PARAMETER;
     688             :         }
     689             : 
     690           6 :         method = http_method_str(req->type);
     691           6 :         if (method == NULL) {
     692           0 :                 return NT_STATUS_INVALID_PARAMETER;
     693             :         }
     694             : 
     695          12 :         str = talloc_asprintf(mem_ctx, "%s %s HTTP/%c.%c\r\n", method,
     696          12 :                               req->uri, req->major, req->minor);
     697           6 :         if (str == NULL)
     698           0 :                 return NT_STATUS_NO_MEMORY;
     699             : 
     700           6 :         if (!data_blob_append(mem_ctx, buffer, str, strlen(str))) {
     701           0 :                 talloc_free(str);
     702           0 :                 return NT_STATUS_NO_MEMORY;
     703             :         }
     704             : 
     705           6 :         talloc_free(str);
     706           6 :         return NT_STATUS_OK;
     707             : }
     708             : 
     709           6 : static NTSTATUS http_push_headers(TALLOC_CTX *mem_ctx,
     710             :                                   DATA_BLOB *blob,
     711             :                                   struct http_request *req)
     712             : {
     713           6 :         struct http_header      *header = NULL;
     714           6 :         char                    *header_str = NULL;
     715             :         size_t                  len;
     716             : 
     717             :         /* Sanity checks */
     718           6 :         if (!blob || !req) {
     719           0 :                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
     720           0 :                 return NT_STATUS_INVALID_PARAMETER;
     721             :         }
     722             : 
     723          36 :         for (header = req->headers; header != NULL; header = header->next) {
     724          30 :                 header_str = talloc_asprintf(mem_ctx, "%s: %s\r\n",
     725             :                                              header->key, header->value);
     726          30 :                 if (header_str == NULL) {
     727           0 :                         return NT_STATUS_NO_MEMORY;
     728             :                 }
     729             : 
     730          30 :                 len = strlen(header_str);
     731          30 :                 if (!data_blob_append(mem_ctx, blob, header_str, len)) {
     732           0 :                         talloc_free(header_str);
     733           0 :                         return NT_STATUS_NO_MEMORY;
     734             :                 }
     735          30 :                 talloc_free(header_str);
     736             :         }
     737             : 
     738           6 :         if (!data_blob_append(mem_ctx, blob, "\r\n",2)) {
     739           0 :                 return NT_STATUS_NO_MEMORY;
     740             :         }
     741             : 
     742           6 :         return NT_STATUS_OK;
     743             : }
     744             : 
     745             : 
     746           6 : static NTSTATUS http_push_body(TALLOC_CTX *mem_ctx,
     747             :                                DATA_BLOB *blob,
     748             :                                struct http_request *req)
     749             : {
     750             :         /* Sanity checks */
     751           6 :         if (!blob || !req) {
     752           0 :                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
     753           0 :                 return NT_STATUS_INVALID_PARAMETER;
     754             :         }
     755             : 
     756           6 :         if (req->body.length) {
     757           6 :                 if (!data_blob_append(mem_ctx, blob, req->body.data,
     758             :                                 req->body.length)) {
     759           0 :                         return NT_STATUS_NO_MEMORY;
     760             :                 }
     761             :         }
     762             : 
     763           6 :         return NT_STATUS_OK;
     764             : }
     765             : 
     766             : struct http_send_request_state {
     767             :         struct tevent_context   *ev;
     768             :         struct loadparm_context *lp_ctx;
     769             :         struct cli_credentials  *credentials;
     770             :         struct http_request     *request;
     771             :         DATA_BLOB               buffer;
     772             :         struct iovec            iov;
     773             :         ssize_t                 nwritten;
     774             :         int                     sys_errno;
     775             : };
     776             : 
     777             : /**
     778             :  * Sends and HTTP request
     779             :  */
     780             : static void http_send_request_done(struct tevent_req *);
     781           6 : struct tevent_req *http_send_request_send(TALLOC_CTX *mem_ctx,
     782             :                                           struct tevent_context *ev,
     783             :                                           struct http_conn *http_conn,
     784             :                                           struct http_request *request)
     785             : {
     786             :         struct tevent_req               *req;
     787             :         struct tevent_req               *subreq;
     788           6 :         struct http_send_request_state  *state = NULL;
     789             :         NTSTATUS                        status;
     790             : 
     791           6 :         DEBUG(11, ("%s: Sending HTTP request\n", __func__));
     792             : 
     793             :         /* Sanity checks */
     794           6 :         if (ev == NULL || request == NULL || http_conn == NULL) {
     795           0 :                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
     796           0 :                 return NULL;
     797             :         }
     798             : 
     799           6 :         req = tevent_req_create(mem_ctx, &state, struct http_send_request_state);
     800           6 :         if (req == NULL) {
     801           0 :                 return NULL;
     802             :         }
     803             : 
     804           6 :         state->ev = ev;
     805           6 :         state->request = request;
     806             : 
     807             :         /* Push the request line */
     808           6 :         status = http_push_request_line(state, &state->buffer, state->request);
     809           6 :         if (!NT_STATUS_IS_OK(status)) {
     810           0 :                 tevent_req_nterror(req, status);
     811           0 :                 return tevent_req_post(req, ev);
     812             :         }
     813             : 
     814             :         /* Push the headers */
     815           6 :         status = http_push_headers(mem_ctx, &state->buffer, request);
     816           6 :         if (!NT_STATUS_IS_OK(status)) {
     817           0 :                 tevent_req_nterror(req, status);
     818           0 :                 return tevent_req_post(req, ev);
     819             :         }
     820             : 
     821             :         /* Push the body */
     822           6 :         status = http_push_body(mem_ctx, &state->buffer, request);
     823           6 :         if (!NT_STATUS_IS_OK(status)) {
     824           0 :                 tevent_req_nterror(req, status);
     825           0 :                 return tevent_req_post(req, ev);
     826             :         }
     827             : 
     828           6 :         state->iov.iov_base = (char *) state->buffer.data;
     829           6 :         state->iov.iov_len = state->buffer.length;
     830           6 :         subreq = tstream_writev_queue_send(state,
     831             :                                            ev,
     832             :                                            http_conn->tstreams.active,
     833             :                                            http_conn->send_queue,
     834           6 :                                            &state->iov, 1);
     835           6 :         if (tevent_req_nomem(subreq, req)) {
     836           0 :                 return tevent_req_post(req, ev);
     837             :         }
     838           6 :         tevent_req_set_callback(subreq, http_send_request_done, req);
     839             : 
     840           6 :         return req;
     841             : }
     842             : 
     843           6 : static void http_send_request_done(struct tevent_req *subreq)
     844             : {
     845             :         NTSTATUS                        status;
     846             :         struct tevent_req               *req;
     847             :         struct http_send_request_state  *state;
     848             : 
     849           6 :         req = tevent_req_callback_data(subreq, struct tevent_req);
     850           6 :         state = tevent_req_data(req, struct http_send_request_state);
     851             : 
     852           6 :         state->nwritten = tstream_writev_queue_recv(subreq, &state->sys_errno);
     853           6 :         TALLOC_FREE(subreq);
     854           6 :         if (state->nwritten == -1 && state->sys_errno != 0) {
     855           0 :                 status = map_nt_error_from_unix_common(state->sys_errno);
     856           0 :                 DEBUG(0, ("%s: Failed to send HTTP request: %s\n",
     857             :                           __func__, nt_errstr(status)));
     858           0 :                 tevent_req_nterror(req, status);
     859           0 :                 return;
     860             :         }
     861             : 
     862           6 :         tevent_req_done(req);
     863             : }
     864             : 
     865           6 : NTSTATUS http_send_request_recv(struct tevent_req *req)
     866             : {
     867             :         NTSTATUS status;
     868             : 
     869           6 :         if (!req) {
     870           0 :                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
     871           0 :                 return NT_STATUS_INVALID_PARAMETER;
     872             :         }
     873             : 
     874           6 :         if (tevent_req_is_nterror(req, &status)) {
     875           0 :                 tevent_req_received(req);
     876           0 :                 return status;
     877             :         }
     878             : 
     879           6 :         tevent_req_received(req);
     880             : 
     881           6 :         return NT_STATUS_OK;
     882             : }

Generated by: LCOV version 1.13