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