libcli/http: Optimise reading for content-length
[samba.git] / libcli / http / http.c
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 static int http_response_needs_body(struct http_request *req)
37 {
38         struct http_header *h = NULL;
39
40         if (!req) return -1;
41
42         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                 cmp = strcasecmp(h->key, "Content-Length");
49                 if (cmp != 0) {
50                         continue;
51                 }
52
53                 n = sscanf(h->value, "%llu%c", &v, &c);
54                 if (n != 1) {
55                         return -1;
56                 }
57
58                 req->remaining_content_length = v;
59
60                 if (v != 0) {
61                         return 1;
62                 }
63
64                 return 0;
65         }
66
67         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 static enum http_read_status http_parse_headers(struct http_read_response_state *state)
82 {
83         enum http_read_status   status = HTTP_ALL_DATA_READ;
84         char                    *ptr = NULL;
85         char                    *line = NULL;
86         char                    *key = NULL;
87         char                    *value = NULL;
88         int                     n = 0;
89         int                     ret;
90
91         /* Sanity checks */
92         if (!state || !state->response) {
93                 DEBUG(0, ("%s: Invalid Parameter\n", __func__));
94                 return HTTP_DATA_CORRUPTED;
95         }
96
97         if (state->buffer.length > state->max_headers_size) {
98                 DEBUG(0, ("%s: Headers too long: %zi, maximum length is %zi\n", __func__,
99                           state->buffer.length, state->max_headers_size));
100                 return HTTP_DATA_TOO_LONG;
101         }
102
103         line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
104         if (!line) {
105                 DEBUG(0, ("%s: Memory error\n", __func__));
106                 return HTTP_DATA_CORRUPTED;
107         }
108
109         ptr = strstr(line, "\r\n");
110         if (ptr == NULL) {
111                 TALLOC_FREE(line);
112                 return HTTP_MORE_DATA_EXPECTED;
113         }
114
115         state->response->headers_size += state->buffer.length;
116
117         if (strncmp(line, "\r\n", 2) == 0) {
118                 DEBUG(11,("%s: All headers read\n", __func__));
119
120                 ret = http_response_needs_body(state->response);
121                 switch (ret) {
122                 case 1:
123                         if (state->response->remaining_content_length <= state->max_content_length) {
124                                 DEBUG(11, ("%s: Start of read body\n", __func__));
125                                 state->parser_state = HTTP_READING_BODY;
126                                 break;
127                         }
128                         FALL_THROUGH;
129                 case 0:
130                         DEBUG(11, ("%s: Skipping body for code %d\n", __func__,
131                                    state->response->response_code));
132                         state->parser_state = HTTP_READING_DONE;
133                         break;
134                 case -1:
135                         DEBUG(0, ("%s_: Error in http_response_needs_body\n", __func__));
136                         TALLOC_FREE(line);
137                         return HTTP_DATA_CORRUPTED;
138                         break;
139                 }
140
141                 TALLOC_FREE(line);
142                 return HTTP_ALL_DATA_READ;
143         }
144
145         n = sscanf(line, "%m[^:]: %m[^\r\n]\r\n", &key, &value);
146         if (n != 2) {
147                 DEBUG(0, ("%s: Error parsing header '%s'\n", __func__, line));
148                 status = HTTP_DATA_CORRUPTED;
149                 goto error;
150         }
151
152         if (http_add_header(state->response, &state->response->headers, key, value) == -1) {
153                 DEBUG(0, ("%s: Error adding header\n", __func__));
154                 status = HTTP_DATA_CORRUPTED;
155                 goto error;
156         }
157
158 error:
159         free(key);
160         free(value);
161         TALLOC_FREE(line);
162         return status;
163 }
164
165 /**
166  * Parses the first line of a HTTP response
167  */
168 static bool http_parse_response_line(struct http_read_response_state *state)
169 {
170         bool    status = true;
171         char    *protocol;
172         char    *msg = NULL;
173         char    major;
174         char    minor;
175         int     code;
176         char    *line = NULL;
177         int     n;
178
179         /* Sanity checks */
180         if (!state) {
181                 DEBUG(0, ("%s: Input parameter is NULL\n", __func__));
182                 return false;
183         }
184
185         line = talloc_strndup(state, (char*)state->buffer.data, state->buffer.length);
186         if (!line) {
187                 DEBUG(0, ("%s: Memory error\n", __func__));
188                 return false;
189         }
190
191         n = sscanf(line, "%m[^/]/%c.%c %d %m[^\r\n]\r\n",
192                    &protocol, &major, &minor, &code, &msg);
193
194         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         if (n != 5) {
199                 DEBUG(0, ("%s: Error parsing header\n", __func__));
200                 status = false;
201                 goto error;
202         }
203
204         if (major != '1') {
205                 DEBUG(0, ("%s: Bad HTTP major number '%c'\n", __func__, major));
206                 status = false;
207                 goto error;
208         }
209
210         if (code == 0) {
211                 DEBUG(0, ("%s: Bad response code '%d'\n", __func__, code));
212                 status = false;
213                 goto error;
214         }
215
216         if (msg == NULL) {
217                 DEBUG(0, ("%s: Error parsing HTTP data\n", __func__));
218                 status = false;
219                 goto error;
220         }
221
222         state->response->major = major;
223         state->response->minor = minor;
224         state->response->response_code = code;
225         state->response->response_code_line = talloc_strndup(state->response,
226                                                              msg, strlen(msg));
227
228 error:
229         free(protocol);
230         free(msg);
231         TALLOC_FREE(line);
232         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 static enum http_read_status http_parse_firstline(struct http_read_response_state *state)
246 {
247         enum http_read_status   status = HTTP_ALL_DATA_READ;
248         char                    *ptr = NULL;
249         char                    *line;
250
251         /* Sanity checks */
252         if (!state) {
253                 DEBUG(0, ("%s: Invalid Parameter\n", __func__));
254                 return HTTP_DATA_CORRUPTED;
255         }
256
257         if (state->buffer.length > state->max_headers_size) {
258                 DEBUG(0, ("%s: Headers too long: %zi, maximum length is %zi\n", __func__,
259                           state->buffer.length, state->max_headers_size));
260                 return HTTP_DATA_TOO_LONG;
261         }
262
263         line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
264         if (!line) {
265                 DEBUG(0, ("%s: Not enough memory\n", __func__));
266                 return HTTP_DATA_CORRUPTED;
267         }
268
269         ptr = strstr(line, "\r\n");
270         if (ptr == NULL) {
271                 TALLOC_FREE(line);
272                 return HTTP_MORE_DATA_EXPECTED;
273         }
274
275         state->response->headers_size = state->buffer.length;
276         if (!http_parse_response_line(state)) {
277                 status = HTTP_DATA_CORRUPTED;
278         }
279
280         /* Next state, read HTTP headers */
281         state->parser_state = HTTP_READING_HEADERS;
282
283         TALLOC_FREE(line);
284         return status;
285 }
286
287 static enum http_read_status http_read_body(struct http_read_response_state *state)
288 {
289         struct http_request *resp = state->response;
290
291         if (state->buffer.length < resp->remaining_content_length) {
292                 return HTTP_MORE_DATA_EXPECTED;
293         }
294
295         resp->body = state->buffer;
296         state->buffer = data_blob_null;
297         talloc_steal(resp, resp->body.data);
298         resp->remaining_content_length = 0;
299
300         state->parser_state = HTTP_READING_DONE;
301         return HTTP_ALL_DATA_READ;
302 }
303
304 static enum http_read_status http_read_trailer(struct http_read_response_state *state)
305 {
306         enum http_read_status status = HTTP_DATA_CORRUPTED;
307         /* TODO */
308         return status;
309 }
310
311 static enum http_read_status http_parse_buffer(struct http_read_response_state *state)
312 {
313         if (!state) {
314                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
315                 return HTTP_DATA_CORRUPTED;
316         }
317
318         switch (state->parser_state) {
319                 case HTTP_READING_FIRSTLINE:
320                         return http_parse_firstline(state);
321                 case HTTP_READING_HEADERS:
322                         return http_parse_headers(state);
323                 case HTTP_READING_BODY:
324                         return http_read_body(state);
325                         break;
326                 case HTTP_READING_TRAILER:
327                         return http_read_trailer(state);
328                         break;
329                 case HTTP_READING_DONE:
330                         /* All read */
331                         return HTTP_ALL_DATA_READ;
332                 default:
333                         DEBUG(0, ("%s: Illegal parser state %d\n", __func__,
334                                   state->parser_state));
335                         break;
336         }
337         return HTTP_DATA_CORRUPTED;
338 }
339
340 static int http_header_is_valid_value(const char *value)
341 {
342         const char      *p = NULL;
343
344         /* Sanity checks */
345         if (!value) {
346                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
347                 return -1;
348         }
349         p = value;
350
351         while ((p = strpbrk(p, "\r\n")) != NULL) {
352                 /* Expect only one new line */
353                 p += strspn(p, "\r\n");
354                 /* Expect a space or tab for continuation */
355                 if (*p != ' ' && *p != '\t')
356                         return (0);
357         }
358         return 1;
359 }
360
361 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         struct http_header *tail = NULL;
367         struct http_header *h = NULL;
368
369         /* Sanity checks */
370         if (!headers || !key || !value) {
371                 DEBUG(0, ("Invalid parameter\n"));
372                 return -1;
373         }
374
375
376
377         if (replace) {
378                 for (h = *headers; h != NULL; h = h->next) {
379                         if (strcasecmp(key, h->key) == 0) {
380                                 break;
381                         }
382                 }
383
384                 if (h != NULL) {
385                         /* Replace header value */
386                         if (h->value) {
387                                 talloc_free(h->value);
388                         }
389                         h->value = talloc_strdup(h, value);
390                         DEBUG(11, ("%s: Replaced HTTP header: key '%s', value '%s'\n",
391                                         __func__, h->key, h->value));
392                         return 0;
393                 }
394         }
395
396         /* Add new header */
397         h = talloc(mem_ctx, struct http_header);
398         h->key = talloc_strdup(h, key);
399         h->value = talloc_strdup(h, value);
400         DLIST_ADD_END(*headers, h);
401         tail = DLIST_TAIL(*headers);
402         if (tail != h) {
403                 DEBUG(0, ("%s: Error adding header\n", __func__));
404                 return -1;
405         }
406         DEBUG(11, ("%s: Added HTTP header: key '%s', value '%s'\n",
407                         __func__, h->key, h->value));
408         return 0;
409 }
410
411 int http_add_header(TALLOC_CTX *mem_ctx,
412                     struct http_header **headers,
413                     const char *key, const char *value)
414 {
415         if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
416                 DEBUG(0, ("%s: Dropping illegal header key\n", __func__));
417                 return -1;
418         }
419
420         if (!http_header_is_valid_value(value)) {
421                 DEBUG(0, ("%s: Dropping illegal header value\n", __func__));
422                 return -1;
423         }
424
425         return (http_add_header_internal(mem_ctx, headers, key, value, false));
426 }
427
428 int http_replace_header(TALLOC_CTX *mem_ctx,
429                     struct http_header **headers,
430                     const char *key, const char *value)
431 {
432         if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
433                 DEBUG(0, ("%s: Dropping illegal header key\n", __func__));
434                 return -1;
435         }
436
437         if (!http_header_is_valid_value(value)) {
438                 DEBUG(0, ("%s: Dropping illegal header value\n", __func__));
439                 return -1;
440         }
441
442         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 int http_remove_header(struct http_header **headers, const char *key)
452 {
453         struct http_header *header;
454
455         /* Sanity checks */
456         if (!headers || !key) {
457                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
458                 return -1;
459         }
460
461         for(header = *headers; header != NULL; header = header->next) {
462                 if (strcmp(key, header->key) == 0) {
463                         DLIST_REMOVE(*headers, header);
464                         return 0;
465                 }
466         }
467         return -1;
468 }
469
470 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         if (!stream || !private_data || !_vector || !_count) {
481                 DEBUG(0, ("%s: Invalid Parameter\n", __func__));
482                 return -1;
483         }
484
485         state = talloc_get_type_abort(private_data, struct http_read_response_state);
486         vector = talloc_array(mem_ctx, struct iovec, 1);
487         if (!vector) {
488                 DEBUG(0, ("%s: No more memory\n", __func__));
489                 return -1;
490         }
491
492         if (state->buffer.data == NULL) {
493                 /* Allocate buffer */
494                 state->buffer.data = talloc_zero_array(state, uint8_t, 1);
495                 if (!state->buffer.data) {
496                         DEBUG(0, ("%s: No more memory\n", __func__));
497                         return -1;
498                 }
499                 state->buffer.length = 1;
500
501                 /* Return now, nothing to parse yet */
502                 vector[0].iov_base = (void *)(state->buffer.data);
503                 vector[0].iov_len = 1;
504                 *_vector = vector;
505                 *_count = 1;
506                 return 0;
507         }
508
509         switch (http_parse_buffer(state)) {
510                 case HTTP_ALL_DATA_READ:
511                         if (state->parser_state == HTTP_READING_DONE) {
512                                 /* Full request or response parsed */
513                                 *_vector = NULL;
514                                 *_count = 0;
515                         } else {
516                                 /* Free current buffer and allocate new one */
517                                 TALLOC_FREE(state->buffer.data);
518                                 state->buffer.data = talloc_zero_array(state, uint8_t, 1);
519                                 if (!state->buffer.data) {
520                                         return -1;
521                                 }
522                                 state->buffer.length = 1;
523
524                                 vector[0].iov_base = (void *)(state->buffer.data);
525                                 vector[0].iov_len = 1;
526                                 *_vector = vector;
527                                 *_count = 1;
528                         }
529                         break;
530                 case HTTP_MORE_DATA_EXPECTED: {
531                         size_t toread = 1;
532                         size_t total;
533                         if (state->parser_state == HTTP_READING_BODY) {
534                                 struct http_request *resp = state->response;
535                                 toread = resp->remaining_content_length -
536                                          state->buffer.length;
537                         }
538
539                         total = toread + state->buffer.length;
540
541                         if (total < state->buffer.length)  {
542                                 DBG_ERR("adding %zu to buf len %zu "
543                                         "will overflow\n",
544                                         toread,
545                                         state->buffer.length);
546                                         return -1;
547                         }
548
549                         /*
550                          * test if content-length message exceeds the
551                          * specified max_content_length
552                          * Note: This check wont be hit at the moment
553                          *       due to an existing check in parse_headers
554                          *       which will skip the body. Check is here
555                          *       for completeness and to cater for future
556                          *       code changes.
557                          */
558                         if (state->parser_state == HTTP_READING_BODY) {
559                                 if (total > state->max_content_length)  {
560                                         DBG_ERR("content size %zu exceeds "
561                                                 "max content len %zu\n",
562                                                 total,
563                                                 state->max_content_length);
564                                         return -1;
565                                 }
566                         }
567
568                         state->buffer.data =
569                                 talloc_realloc(state, state->buffer.data,
570                                                uint8_t,
571                                                state->buffer.length + toread);
572                         if (!state->buffer.data) {
573                                 return -1;
574                         }
575                         state->buffer.length += toread;
576                         vector[0].iov_base = (void *)(state->buffer.data +
577                                              state->buffer.length - toread);
578                         vector[0].iov_len = toread;
579                         *_vector = vector;
580                         *_count = 1;
581                         break;
582                 }
583                 case HTTP_DATA_CORRUPTED:
584                 case HTTP_REQUEST_CANCELED:
585                 case HTTP_DATA_TOO_LONG:
586                         return -1;
587                         break;
588                 default:
589                         DEBUG(0, ("%s: Unexpected status\n", __func__));
590                         break;
591         }
592         return 0;
593 }
594
595
596 /**
597  * Reads a HTTP response
598  */
599 static void http_read_response_done(struct tevent_req *);
600 struct tevent_req *http_read_response_send(TALLOC_CTX *mem_ctx,
601                                            struct tevent_context *ev,
602                                            struct http_conn *http_conn,
603                                            size_t max_content_length)
604 {
605         struct tevent_req               *req;
606         struct tevent_req               *subreq;
607         struct http_read_response_state *state;
608
609         DEBUG(11, ("%s: Reading HTTP response\n", __func__));
610
611         /* Sanity checks */
612         if (ev == NULL || http_conn == NULL) {
613                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
614                 return NULL;
615         }
616
617         req = tevent_req_create(mem_ctx, &state, struct http_read_response_state);
618         if (req == NULL) {
619                 return NULL;
620         }
621
622         state->max_headers_size = HTTP_MAX_HEADER_SIZE;
623         state->max_content_length = (uint64_t)max_content_length;
624         state->parser_state = HTTP_READING_FIRSTLINE;
625         state->response = talloc_zero(state, struct http_request);
626         if (tevent_req_nomem(state->response, req)) {
627                 return tevent_req_post(req, ev);
628         }
629
630         subreq = tstream_readv_pdu_send(state, ev, http_conn->tstreams.active,
631                                         http_read_response_next_vector,
632                                         state);
633         if (tevent_req_nomem(subreq,req)) {
634                 return tevent_req_post(req, ev);
635         }
636         tevent_req_set_callback(subreq, http_read_response_done, req);
637
638         return req;
639 }
640
641 static void http_read_response_done(struct tevent_req *subreq)
642 {
643         NTSTATUS                        status;
644         struct tevent_req               *req;
645         int                             ret;
646         int                             sys_errno;
647
648         if (!subreq) {
649                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
650                 return;
651         }
652
653         req = tevent_req_callback_data(subreq, struct tevent_req);
654
655         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
656         DEBUG(11, ("%s: HTTP response read (%d bytes)\n", __func__, ret));
657         TALLOC_FREE(subreq);
658         if (ret == -1) {
659                 status = map_nt_error_from_unix_common(sys_errno);
660                 DEBUG(0, ("%s: Failed to read HTTP response: %s\n",
661                           __func__, nt_errstr(status)));
662                 tevent_req_nterror(req, status);
663                 return;
664         }
665
666         tevent_req_done(req);
667 }
668
669 NTSTATUS http_read_response_recv(struct tevent_req *req,
670                                  TALLOC_CTX *mem_ctx,
671                                  struct http_request **response)
672 {
673         NTSTATUS status;
674         struct http_read_response_state *state;
675
676         if (!mem_ctx || !response || !req) {
677                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
678                 return NT_STATUS_INVALID_PARAMETER;
679         }
680         if (tevent_req_is_nterror(req, &status)) {
681                 tevent_req_received(req);
682                 return status;
683         }
684
685         state = tevent_req_data(req, struct http_read_response_state);
686         *response = state->response;
687         talloc_steal(mem_ctx, state->response);
688
689         tevent_req_received(req);
690
691         return NT_STATUS_OK;
692 }
693
694 static const char *http_method_str(enum http_cmd_type type)
695 {
696         const char *method;
697
698         switch (type) {
699         case HTTP_REQ_POST:
700                 method = "POST";
701                 break;
702         case HTTP_REQ_RPC_IN_DATA:
703                 method = "RPC_IN_DATA";
704                 break;
705         case HTTP_REQ_RPC_OUT_DATA:
706                 method = "RPC_OUT_DATA";
707                 break;
708         default:
709                 method = NULL;
710                 break;
711         }
712
713         return method;
714 }
715
716 static NTSTATUS http_push_request_line(TALLOC_CTX *mem_ctx,
717                                        DATA_BLOB *buffer,
718                                        const struct http_request *req)
719 {
720         const char      *method;
721         char            *str;
722
723         /* Sanity checks */
724         if (!buffer || !req) {
725                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
726                 return NT_STATUS_INVALID_PARAMETER;
727         }
728
729         method = http_method_str(req->type);
730         if (method == NULL) {
731                 return NT_STATUS_INVALID_PARAMETER;
732         }
733
734         str = talloc_asprintf(mem_ctx, "%s %s HTTP/%c.%c\r\n", method,
735                               req->uri, req->major, req->minor);
736         if (str == NULL)
737                 return NT_STATUS_NO_MEMORY;
738
739         if (!data_blob_append(mem_ctx, buffer, str, strlen(str))) {
740                 talloc_free(str);
741                 return NT_STATUS_NO_MEMORY;
742         }
743
744         talloc_free(str);
745         return NT_STATUS_OK;
746 }
747
748 static NTSTATUS http_push_headers(TALLOC_CTX *mem_ctx,
749                                   DATA_BLOB *blob,
750                                   struct http_request *req)
751 {
752         struct http_header      *header = NULL;
753         char                    *header_str = NULL;
754         size_t                  len;
755
756         /* Sanity checks */
757         if (!blob || !req) {
758                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
759                 return NT_STATUS_INVALID_PARAMETER;
760         }
761
762         for (header = req->headers; header != NULL; header = header->next) {
763                 header_str = talloc_asprintf(mem_ctx, "%s: %s\r\n",
764                                              header->key, header->value);
765                 if (header_str == NULL) {
766                         return NT_STATUS_NO_MEMORY;
767                 }
768
769                 len = strlen(header_str);
770                 if (!data_blob_append(mem_ctx, blob, header_str, len)) {
771                         talloc_free(header_str);
772                         return NT_STATUS_NO_MEMORY;
773                 }
774                 talloc_free(header_str);
775         }
776
777         if (!data_blob_append(mem_ctx, blob, "\r\n",2)) {
778                 return NT_STATUS_NO_MEMORY;
779         }
780
781         return NT_STATUS_OK;
782 }
783
784
785 static NTSTATUS http_push_body(TALLOC_CTX *mem_ctx,
786                                DATA_BLOB *blob,
787                                struct http_request *req)
788 {
789         /* Sanity checks */
790         if (!blob || !req) {
791                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
792                 return NT_STATUS_INVALID_PARAMETER;
793         }
794
795         if (req->body.length) {
796                 if (!data_blob_append(mem_ctx, blob, req->body.data,
797                                 req->body.length)) {
798                         return NT_STATUS_NO_MEMORY;
799                 }
800         }
801
802         return NT_STATUS_OK;
803 }
804
805 struct http_send_request_state {
806         struct tevent_context   *ev;
807         struct loadparm_context *lp_ctx;
808         struct cli_credentials  *credentials;
809         struct http_request     *request;
810         DATA_BLOB               buffer;
811         struct iovec            iov;
812         ssize_t                 nwritten;
813         int                     sys_errno;
814 };
815
816 /**
817  * Sends and HTTP request
818  */
819 static void http_send_request_done(struct tevent_req *);
820 struct tevent_req *http_send_request_send(TALLOC_CTX *mem_ctx,
821                                           struct tevent_context *ev,
822                                           struct http_conn *http_conn,
823                                           struct http_request *request)
824 {
825         struct tevent_req               *req;
826         struct tevent_req               *subreq;
827         struct http_send_request_state  *state = NULL;
828         NTSTATUS                        status;
829
830         DEBUG(11, ("%s: Sending HTTP request\n", __func__));
831
832         /* Sanity checks */
833         if (ev == NULL || request == NULL || http_conn == NULL) {
834                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
835                 return NULL;
836         }
837
838         req = tevent_req_create(mem_ctx, &state, struct http_send_request_state);
839         if (req == NULL) {
840                 return NULL;
841         }
842
843         state->ev = ev;
844         state->request = request;
845
846         /* Push the request line */
847         status = http_push_request_line(state, &state->buffer, state->request);
848         if (!NT_STATUS_IS_OK(status)) {
849                 tevent_req_nterror(req, status);
850                 return tevent_req_post(req, ev);
851         }
852
853         /* Push the headers */
854         status = http_push_headers(mem_ctx, &state->buffer, request);
855         if (!NT_STATUS_IS_OK(status)) {
856                 tevent_req_nterror(req, status);
857                 return tevent_req_post(req, ev);
858         }
859
860         /* Push the body */
861         status = http_push_body(mem_ctx, &state->buffer, request);
862         if (!NT_STATUS_IS_OK(status)) {
863                 tevent_req_nterror(req, status);
864                 return tevent_req_post(req, ev);
865         }
866
867         state->iov.iov_base = (char *) state->buffer.data;
868         state->iov.iov_len = state->buffer.length;
869         subreq = tstream_writev_queue_send(state,
870                                            ev,
871                                            http_conn->tstreams.active,
872                                            http_conn->send_queue,
873                                            &state->iov, 1);
874         if (tevent_req_nomem(subreq, req)) {
875                 return tevent_req_post(req, ev);
876         }
877         tevent_req_set_callback(subreq, http_send_request_done, req);
878
879         return req;
880 }
881
882 static void http_send_request_done(struct tevent_req *subreq)
883 {
884         NTSTATUS                        status;
885         struct tevent_req               *req;
886         struct http_send_request_state  *state;
887
888         req = tevent_req_callback_data(subreq, struct tevent_req);
889         state = tevent_req_data(req, struct http_send_request_state);
890
891         state->nwritten = tstream_writev_queue_recv(subreq, &state->sys_errno);
892         TALLOC_FREE(subreq);
893         if (state->nwritten == -1 && state->sys_errno != 0) {
894                 status = map_nt_error_from_unix_common(state->sys_errno);
895                 DEBUG(0, ("%s: Failed to send HTTP request: %s\n",
896                           __func__, nt_errstr(status)));
897                 tevent_req_nterror(req, status);
898                 return;
899         }
900
901         tevent_req_done(req);
902 }
903
904 NTSTATUS http_send_request_recv(struct tevent_req *req)
905 {
906         NTSTATUS status;
907
908         if (!req) {
909                 DEBUG(0, ("%s: Invalid parameter\n", __func__));
910                 return NT_STATUS_INVALID_PARAMETER;
911         }
912
913         if (tevent_req_is_nterror(req, &status)) {
914                 tevent_req_received(req);
915                 return status;
916         }
917
918         tevent_req_received(req);
919
920         return NT_STATUS_OK;
921 }