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