2 Unix SMB/CIFS implementation.
6 Copyright (C) 2013 Samuel Cabrero <samuelcabrero@kernevil.me>
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.
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.
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/>.
23 #include "lib/util/tevent_ntstatus.h"
25 #include "http_internal.h"
26 #include "util/tevent_werror.h"
27 #include "lib/util/dlinklist.h"
39 * Determines if a response should have a body.
40 * @return 2 if response MUST use chunked encoding,
41 * 1 if the response MUST have a body;
42 * 0 if the response MUST NOT have a body.
43 * Returns -1 on error.
45 static enum http_body_type
http_response_needs_body(
46 struct http_request
*req
)
48 struct http_header
*h
= NULL
;
54 for (h
= req
->headers
; h
!= NULL
; h
= h
->next
) {
60 cmp
= strcasecmp(h
->key
, "Transfer-Encoding");
62 cmp
= strcasecmp(h
->value
, "chunked");
66 /* unsupported Transfer-Encoding type */
67 DBG_ERR("Unsupported transfer encoding type %s\n",
72 cmp
= strcasecmp(h
->key
, "Content-Length");
77 n
= sscanf(h
->value
, "%llu%c", &v
, &c
);
82 req
->remaining_content_length
= v
;
85 return BODY_CONTENT_LENGTH
;
95 struct http_chunk
*prev
, *next
;
99 struct http_read_response_state
{
100 enum http_parser_state parser_state
;
101 size_t max_headers_size
;
102 uint64_t max_content_length
;
104 struct http_request
*response
;
105 struct http_chunk
*chunks
;
109 * Parses the HTTP headers
111 static enum http_read_status
http_parse_headers(struct http_read_response_state
*state
)
113 enum http_read_status status
= HTTP_ALL_DATA_READ
;
119 enum http_body_type ret
;
122 if (!state
|| !state
->response
) {
123 DEBUG(0, ("%s: Invalid Parameter\n", __func__
));
124 return HTTP_DATA_CORRUPTED
;
127 if (state
->buffer
.length
> state
->max_headers_size
) {
128 DEBUG(0, ("%s: Headers too long: %zi, maximum length is %zi\n", __func__
,
129 state
->buffer
.length
, state
->max_headers_size
));
130 return HTTP_DATA_TOO_LONG
;
133 line
= talloc_strndup(state
, (char *)state
->buffer
.data
, state
->buffer
.length
);
135 DEBUG(0, ("%s: Memory error\n", __func__
));
136 return HTTP_DATA_CORRUPTED
;
139 ptr
= strstr(line
, "\r\n");
142 return HTTP_MORE_DATA_EXPECTED
;
145 state
->response
->headers_size
+= state
->buffer
.length
;
147 if (strncmp(line
, "\r\n", 2) == 0) {
148 DEBUG(11,("%s: All headers read\n", __func__
));
150 ret
= http_response_needs_body(state
->response
);
153 DEBUG(11, ("%s: need to process chunks... %d\n", __func__
,
154 state
->response
->response_code
));
155 state
->parser_state
= HTTP_READING_CHUNK_SIZE
;
157 case BODY_CONTENT_LENGTH
:
158 if (state
->response
->remaining_content_length
<= state
->max_content_length
) {
159 DEBUG(11, ("%s: Start of read body\n", __func__
));
160 state
->parser_state
= HTTP_READING_BODY
;
165 DEBUG(11, ("%s: Skipping body for code %d\n", __func__
,
166 state
->response
->response_code
));
167 state
->parser_state
= HTTP_READING_DONE
;
170 DEBUG(0, ("%s_: Error in http_response_needs_body\n", __func__
));
172 return HTTP_DATA_CORRUPTED
;
177 return HTTP_ALL_DATA_READ
;
180 n
= sscanf(line
, "%m[^:]: %m[^\r\n]\r\n", &key
, &value
);
182 DEBUG(0, ("%s: Error parsing header '%s'\n", __func__
, line
));
183 status
= HTTP_DATA_CORRUPTED
;
187 if (http_add_header(state
->response
, &state
->response
->headers
, key
, value
) == -1) {
188 DEBUG(0, ("%s: Error adding header\n", __func__
));
189 status
= HTTP_DATA_CORRUPTED
;
200 static bool http_response_process_chunks(struct http_read_response_state
*state
)
202 struct http_chunk
*chunk
= NULL
;
203 struct http_request
*resp
= state
->response
;
205 for (chunk
= state
->chunks
; chunk
; chunk
= chunk
->next
) {
206 DBG_DEBUG("processing chunk of size %zi\n",
208 if (resp
->body
.data
== NULL
) {
209 resp
->body
= chunk
->blob
;
210 chunk
->blob
= data_blob_null
;
211 talloc_steal(resp
, resp
->body
.data
);
219 resp
->body
.length
+ chunk
->blob
.length
);
220 if (!resp
->body
.data
) {
223 memcpy(resp
->body
.data
+ resp
->body
.length
,
227 resp
->body
.length
+= chunk
->blob
.length
;
229 TALLOC_FREE(chunk
->blob
.data
);
230 chunk
->blob
= data_blob_null
;
235 static enum http_read_status
http_read_chunk_term(struct http_read_response_state
*state
)
237 enum http_read_status status
= HTTP_ALL_DATA_READ
;
242 if (!state
|| !state
->response
) {
243 DBG_ERR("%s: Invalid Parameter\n", __func__
);
244 return HTTP_DATA_CORRUPTED
;
247 line
= talloc_strndup(state
, (char *)state
->buffer
.data
, state
->buffer
.length
);
249 DBG_ERR("%s: Memory error\n", __func__
);
250 return HTTP_DATA_CORRUPTED
;
252 ptr
= strstr(line
, "\r\n");
255 return HTTP_MORE_DATA_EXPECTED
;
258 if (strncmp(line
, "\r\n", 2) == 0) {
259 /* chunk terminator */
260 if (state
->parser_state
== HTTP_READING_FINAL_CHUNK_TERM
) {
261 if (http_response_process_chunks(state
) == false) {
262 status
= HTTP_DATA_CORRUPTED
;
265 state
->parser_state
= HTTP_READING_DONE
;
267 state
->parser_state
= HTTP_READING_CHUNK_SIZE
;
269 status
= HTTP_ALL_DATA_READ
;
273 status
= HTTP_DATA_CORRUPTED
;
279 static enum http_read_status
http_read_chunk_size(struct http_read_response_state
*state
)
281 enum http_read_status status
= HTTP_ALL_DATA_READ
;
286 unsigned long long v
;
289 if (!state
|| !state
->response
) {
290 DBG_ERR("%s: Invalid Parameter\n", __func__
);
291 return HTTP_DATA_CORRUPTED
;
294 line
= talloc_strndup(state
, (char *)state
->buffer
.data
, state
->buffer
.length
);
296 DBG_ERR("%s: Memory error\n", __func__
);
297 return HTTP_DATA_CORRUPTED
;
299 ptr
= strstr(line
, "\r\n");
302 return HTTP_MORE_DATA_EXPECTED
;
305 n
= sscanf(line
, "%m[^\r\n]\r\n", &value
);
307 DBG_ERR("%s: Error parsing chunk size '%s'\n", __func__
, line
);
308 status
= HTTP_DATA_CORRUPTED
;
312 DBG_DEBUG("Got chunk size string %s\n", value
);
313 n
= sscanf(value
, "%llx", &v
);
315 DBG_ERR("%s: Error parsing chunk size '%s'\n", __func__
, line
);
316 status
= HTTP_DATA_CORRUPTED
;
319 DBG_DEBUG("Got chunk size %llu 0x%llx\n", v
, v
);
321 state
->parser_state
= HTTP_READING_FINAL_CHUNK_TERM
;
323 state
->parser_state
= HTTP_READING_CHUNK
;
325 state
->response
->remaining_content_length
= v
;
326 status
= HTTP_ALL_DATA_READ
;
336 * Parses the first line of a HTTP response
338 static bool http_parse_response_line(struct http_read_response_state
*state
)
351 DEBUG(0, ("%s: Input parameter is NULL\n", __func__
));
355 line
= talloc_strndup(state
, (char*)state
->buffer
.data
, state
->buffer
.length
);
357 DEBUG(0, ("%s: Memory error\n", __func__
));
361 n
= sscanf(line
, "%m[^/]/%c.%c %d %m[^\r\n]\r\n",
362 &protocol
, &major
, &minor
, &code
, &msg
);
364 DEBUG(11, ("%s: Header parsed(%i): protocol->%s, major->%c, minor->%c, "
365 "code->%d, message->%s\n", __func__
, n
, protocol
, major
, minor
,
369 DEBUG(0, ("%s: Error parsing header\n", __func__
));
375 DEBUG(0, ("%s: Bad HTTP major number '%c'\n", __func__
, major
));
381 DEBUG(0, ("%s: Bad response code '%d'\n", __func__
, code
));
387 DEBUG(0, ("%s: Error parsing HTTP data\n", __func__
));
392 state
->response
->major
= major
;
393 state
->response
->minor
= minor
;
394 state
->response
->response_code
= code
;
395 state
->response
->response_code_line
= talloc_strndup(state
->response
,
406 * Parses header lines from a request or a response into the specified
407 * request object given a buffer.
410 * HTTP_DATA_CORRUPTED on error
411 * HTTP_MORE_DATA_EXPECTED when we need to read more headers
412 * HTTP_DATA_TOO_LONG on error
413 * HTTP_ALL_DATA_READ when all headers have been read
415 static enum http_read_status
http_parse_firstline(struct http_read_response_state
*state
)
417 enum http_read_status status
= HTTP_ALL_DATA_READ
;
423 DEBUG(0, ("%s: Invalid Parameter\n", __func__
));
424 return HTTP_DATA_CORRUPTED
;
427 if (state
->buffer
.length
> state
->max_headers_size
) {
428 DEBUG(0, ("%s: Headers too long: %zi, maximum length is %zi\n", __func__
,
429 state
->buffer
.length
, state
->max_headers_size
));
430 return HTTP_DATA_TOO_LONG
;
433 line
= talloc_strndup(state
, (char *)state
->buffer
.data
, state
->buffer
.length
);
435 DEBUG(0, ("%s: Not enough memory\n", __func__
));
436 return HTTP_DATA_CORRUPTED
;
439 ptr
= strstr(line
, "\r\n");
442 return HTTP_MORE_DATA_EXPECTED
;
445 state
->response
->headers_size
= state
->buffer
.length
;
446 if (!http_parse_response_line(state
)) {
447 status
= HTTP_DATA_CORRUPTED
;
450 /* Next state, read HTTP headers */
451 state
->parser_state
= HTTP_READING_HEADERS
;
457 static enum http_read_status
http_read_body(struct http_read_response_state
*state
)
459 struct http_request
*resp
= state
->response
;
461 if (state
->buffer
.length
< resp
->remaining_content_length
) {
462 return HTTP_MORE_DATA_EXPECTED
;
465 resp
->body
= state
->buffer
;
466 state
->buffer
= data_blob_null
;
467 talloc_steal(resp
, resp
->body
.data
);
468 resp
->remaining_content_length
= 0;
470 state
->parser_state
= HTTP_READING_DONE
;
471 return HTTP_ALL_DATA_READ
;
474 static enum http_read_status
http_read_chunk(struct http_read_response_state
*state
)
476 struct http_request
*resp
= state
->response
;
477 struct http_chunk
*chunk
= NULL
;
481 if (state
->buffer
.length
< resp
->remaining_content_length
) {
482 return HTTP_MORE_DATA_EXPECTED
;
485 for (chunk
= state
->chunks
; chunk
; chunk
= chunk
->next
) {
486 total
+= chunk
->blob
.length
;
490 total
= total
+ state
->buffer
.length
;
492 DBG_ERR("adding chunklen %zu to buf len %zu "
494 state
->buffer
.length
,
496 return HTTP_DATA_CORRUPTED
;
498 if (total
> state
->max_content_length
) {
499 DBG_DEBUG("size %zu exceeds "
500 "max content len %"PRIu64
" skipping body\n",
502 state
->max_content_length
);
503 state
->parser_state
= HTTP_READING_DONE
;
508 chunk
= talloc_zero(state
, struct http_chunk
);
510 DBG_ERR("%s: Memory error\n", __func__
);
511 return HTTP_DATA_CORRUPTED
;
513 chunk
->blob
= state
->buffer
;
514 talloc_steal(chunk
, chunk
->blob
.data
);
515 DLIST_ADD_END(state
->chunks
, chunk
);
516 state
->parser_state
= HTTP_READING_CHUNK_TERM
;
518 state
->buffer
= data_blob_null
;
519 resp
->remaining_content_length
= 0;
520 return HTTP_ALL_DATA_READ
;
523 static enum http_read_status
http_read_trailer(struct http_read_response_state
*state
)
525 enum http_read_status status
= HTTP_DATA_CORRUPTED
;
530 static enum http_read_status
http_parse_buffer(struct http_read_response_state
*state
)
533 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
534 return HTTP_DATA_CORRUPTED
;
537 switch (state
->parser_state
) {
538 case HTTP_READING_FIRSTLINE
:
539 return http_parse_firstline(state
);
540 case HTTP_READING_HEADERS
:
541 return http_parse_headers(state
);
542 case HTTP_READING_BODY
:
543 return http_read_body(state
);
545 case HTTP_READING_FINAL_CHUNK_TERM
:
546 case HTTP_READING_CHUNK_TERM
:
547 return http_read_chunk_term(state
);
549 case HTTP_READING_CHUNK_SIZE
:
550 return http_read_chunk_size(state
);
552 case HTTP_READING_CHUNK
:
553 return http_read_chunk(state
);
555 case HTTP_READING_TRAILER
:
556 return http_read_trailer(state
);
558 case HTTP_READING_DONE
:
560 return HTTP_ALL_DATA_READ
;
562 DEBUG(0, ("%s: Illegal parser state %d\n", __func__
,
563 state
->parser_state
));
566 return HTTP_DATA_CORRUPTED
;
569 static int http_header_is_valid_value(const char *value
)
571 const char *p
= NULL
;
575 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
580 while ((p
= strpbrk(p
, "\r\n")) != NULL
) {
581 /* Expect only one new line */
582 p
+= strspn(p
, "\r\n");
583 /* Expect a space or tab for continuation */
584 if (*p
!= ' ' && *p
!= '\t')
590 static int http_add_header_internal(TALLOC_CTX
*mem_ctx
,
591 struct http_header
**headers
,
592 const char *key
, const char *value
,
595 struct http_header
*tail
= NULL
;
596 struct http_header
*h
= NULL
;
599 if (!headers
|| !key
|| !value
) {
600 DEBUG(0, ("Invalid parameter\n"));
607 for (h
= *headers
; h
!= NULL
; h
= h
->next
) {
608 if (strcasecmp(key
, h
->key
) == 0) {
614 /* Replace header value */
616 talloc_free(h
->value
);
618 h
->value
= talloc_strdup(h
, value
);
619 DEBUG(11, ("%s: Replaced HTTP header: key '%s', value '%s'\n",
620 __func__
, h
->key
, h
->value
));
626 h
= talloc(mem_ctx
, struct http_header
);
627 h
->key
= talloc_strdup(h
, key
);
628 h
->value
= talloc_strdup(h
, value
);
629 DLIST_ADD_END(*headers
, h
);
630 tail
= DLIST_TAIL(*headers
);
632 DEBUG(0, ("%s: Error adding header\n", __func__
));
635 DEBUG(11, ("%s: Added HTTP header: key '%s', value '%s'\n",
636 __func__
, h
->key
, h
->value
));
640 int http_add_header(TALLOC_CTX
*mem_ctx
,
641 struct http_header
**headers
,
642 const char *key
, const char *value
)
644 if (strchr(key
, '\r') != NULL
|| strchr(key
, '\n') != NULL
) {
645 DEBUG(0, ("%s: Dropping illegal header key\n", __func__
));
649 if (!http_header_is_valid_value(value
)) {
650 DEBUG(0, ("%s: Dropping illegal header value\n", __func__
));
654 return (http_add_header_internal(mem_ctx
, headers
, key
, value
, false));
657 int http_replace_header(TALLOC_CTX
*mem_ctx
,
658 struct http_header
**headers
,
659 const char *key
, const char *value
)
661 if (strchr(key
, '\r') != NULL
|| strchr(key
, '\n') != NULL
) {
662 DEBUG(0, ("%s: Dropping illegal header key\n", __func__
));
666 if (!http_header_is_valid_value(value
)) {
667 DEBUG(0, ("%s: Dropping illegal header value\n", __func__
));
671 return (http_add_header_internal(mem_ctx
, headers
, key
, value
, true));
675 * Remove a header from the headers list.
677 * Returns 0, if the header was successfully removed.
678 * Returns -1, if the header could not be found.
680 int http_remove_header(struct http_header
**headers
, const char *key
)
682 struct http_header
*header
;
685 if (!headers
|| !key
) {
686 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
690 for(header
= *headers
; header
!= NULL
; header
= header
->next
) {
691 if (strcmp(key
, header
->key
) == 0) {
692 DLIST_REMOVE(*headers
, header
);
699 static int http_read_response_next_vector(struct tstream_context
*stream
,
702 struct iovec
**_vector
,
705 struct http_read_response_state
*state
;
706 struct iovec
*vector
;
709 if (!stream
|| !private_data
|| !_vector
|| !_count
) {
710 DEBUG(0, ("%s: Invalid Parameter\n", __func__
));
714 state
= talloc_get_type_abort(private_data
, struct http_read_response_state
);
715 vector
= talloc_array(mem_ctx
, struct iovec
, 1);
717 DEBUG(0, ("%s: No more memory\n", __func__
));
721 if (state
->buffer
.data
== NULL
) {
722 /* Allocate buffer */
723 state
->buffer
.data
= talloc_zero_array(state
, uint8_t, 1);
724 if (!state
->buffer
.data
) {
725 DEBUG(0, ("%s: No more memory\n", __func__
));
728 state
->buffer
.length
= 1;
730 /* Return now, nothing to parse yet */
731 vector
[0].iov_base
= (void *)(state
->buffer
.data
);
732 vector
[0].iov_len
= 1;
738 switch (http_parse_buffer(state
)) {
739 case HTTP_ALL_DATA_READ
:
740 if (state
->parser_state
== HTTP_READING_DONE
) {
741 /* Full request or response parsed */
745 /* Free current buffer and allocate new one */
746 TALLOC_FREE(state
->buffer
.data
);
747 state
->buffer
.data
= talloc_zero_array(state
, uint8_t, 1);
748 if (!state
->buffer
.data
) {
751 state
->buffer
.length
= 1;
753 vector
[0].iov_base
= (void *)(state
->buffer
.data
);
754 vector
[0].iov_len
= 1;
759 case HTTP_MORE_DATA_EXPECTED
: {
762 if (state
->parser_state
== HTTP_READING_BODY
||
763 state
->parser_state
== HTTP_READING_CHUNK
) {
764 struct http_request
*resp
= state
->response
;
765 toread
= resp
->remaining_content_length
-
766 state
->buffer
.length
;
769 total
= toread
+ state
->buffer
.length
;
771 if (total
< state
->buffer
.length
) {
772 DBG_ERR("adding %zu to buf len %zu "
775 state
->buffer
.length
);
780 * test if content-length message exceeds the
781 * specified max_content_length
782 * Note: This check won't be hit at the moment
783 * due to an existing check in parse_headers
784 * which will skip the body. Check is here
785 * for completeness and to cater for future
788 if (state
->parser_state
== HTTP_READING_BODY
) {
789 if (total
> state
->max_content_length
) {
790 DBG_ERR("content size %zu exceeds "
791 "max content len %"PRIu64
"\n",
793 state
->max_content_length
);
799 talloc_realloc(state
, state
->buffer
.data
,
801 state
->buffer
.length
+ toread
);
802 if (!state
->buffer
.data
) {
805 state
->buffer
.length
+= toread
;
806 vector
[0].iov_base
= (void *)(state
->buffer
.data
+
807 state
->buffer
.length
- toread
);
808 vector
[0].iov_len
= toread
;
813 case HTTP_DATA_CORRUPTED
:
814 case HTTP_REQUEST_CANCELED
:
815 case HTTP_DATA_TOO_LONG
:
819 DEBUG(0, ("%s: Unexpected status\n", __func__
));
827 * Reads a HTTP response
829 static void http_read_response_done(struct tevent_req
*);
830 struct tevent_req
*http_read_response_send(TALLOC_CTX
*mem_ctx
,
831 struct tevent_context
*ev
,
832 struct http_conn
*http_conn
,
833 size_t max_content_length
)
835 struct tevent_req
*req
;
836 struct tevent_req
*subreq
;
837 struct http_read_response_state
*state
;
839 DEBUG(11, ("%s: Reading HTTP response\n", __func__
));
842 if (ev
== NULL
|| http_conn
== NULL
) {
843 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
847 req
= tevent_req_create(mem_ctx
, &state
, struct http_read_response_state
);
852 state
->max_headers_size
= HTTP_MAX_HEADER_SIZE
;
853 state
->max_content_length
= (uint64_t)max_content_length
;
854 state
->parser_state
= HTTP_READING_FIRSTLINE
;
855 state
->response
= talloc_zero(state
, struct http_request
);
856 if (tevent_req_nomem(state
->response
, req
)) {
857 return tevent_req_post(req
, ev
);
860 subreq
= tstream_readv_pdu_send(state
, ev
, http_conn
->tstreams
.active
,
861 http_read_response_next_vector
,
863 if (tevent_req_nomem(subreq
,req
)) {
864 return tevent_req_post(req
, ev
);
866 tevent_req_set_callback(subreq
, http_read_response_done
, req
);
871 static void http_read_response_done(struct tevent_req
*subreq
)
874 struct tevent_req
*req
;
875 enum http_body_type ret
;
879 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
883 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
885 ret
= tstream_readv_pdu_recv(subreq
, &sys_errno
);
886 DEBUG(11, ("%s: HTTP response read (%d bytes)\n", __func__
, ret
));
889 status
= map_nt_error_from_unix_common(sys_errno
);
890 DEBUG(0, ("%s: Failed to read HTTP response: %s\n",
891 __func__
, nt_errstr(status
)));
892 tevent_req_nterror(req
, status
);
896 tevent_req_done(req
);
899 NTSTATUS
http_read_response_recv(struct tevent_req
*req
,
901 struct http_request
**response
)
904 struct http_read_response_state
*state
;
906 if (!mem_ctx
|| !response
|| !req
) {
907 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
908 return NT_STATUS_INVALID_PARAMETER
;
910 if (tevent_req_is_nterror(req
, &status
)) {
911 tevent_req_received(req
);
915 state
= tevent_req_data(req
, struct http_read_response_state
);
916 *response
= state
->response
;
917 talloc_steal(mem_ctx
, state
->response
);
919 tevent_req_received(req
);
924 static const char *http_method_str(enum http_cmd_type type
)
932 case HTTP_REQ_RPC_IN_DATA
:
933 method
= "RPC_IN_DATA";
935 case HTTP_REQ_RPC_OUT_DATA
:
936 method
= "RPC_OUT_DATA";
946 static NTSTATUS
http_push_request_line(TALLOC_CTX
*mem_ctx
,
948 const struct http_request
*req
)
954 if (!buffer
|| !req
) {
955 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
956 return NT_STATUS_INVALID_PARAMETER
;
959 method
= http_method_str(req
->type
);
960 if (method
== NULL
) {
961 return NT_STATUS_INVALID_PARAMETER
;
964 str
= talloc_asprintf(mem_ctx
, "%s %s HTTP/%c.%c\r\n", method
,
965 req
->uri
, req
->major
, req
->minor
);
967 return NT_STATUS_NO_MEMORY
;
969 if (!data_blob_append(mem_ctx
, buffer
, str
, strlen(str
))) {
971 return NT_STATUS_NO_MEMORY
;
978 static NTSTATUS
http_push_headers(TALLOC_CTX
*mem_ctx
,
980 struct http_request
*req
)
982 struct http_header
*header
= NULL
;
983 char *header_str
= NULL
;
988 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
989 return NT_STATUS_INVALID_PARAMETER
;
992 for (header
= req
->headers
; header
!= NULL
; header
= header
->next
) {
993 header_str
= talloc_asprintf(mem_ctx
, "%s: %s\r\n",
994 header
->key
, header
->value
);
995 if (header_str
== NULL
) {
996 return NT_STATUS_NO_MEMORY
;
999 len
= strlen(header_str
);
1000 if (!data_blob_append(mem_ctx
, blob
, header_str
, len
)) {
1001 talloc_free(header_str
);
1002 return NT_STATUS_NO_MEMORY
;
1004 talloc_free(header_str
);
1007 if (!data_blob_append(mem_ctx
, blob
, "\r\n",2)) {
1008 return NT_STATUS_NO_MEMORY
;
1011 return NT_STATUS_OK
;
1015 static NTSTATUS
http_push_body(TALLOC_CTX
*mem_ctx
,
1017 struct http_request
*req
)
1020 if (!blob
|| !req
) {
1021 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
1022 return NT_STATUS_INVALID_PARAMETER
;
1025 if (req
->body
.length
) {
1026 if (!data_blob_append(mem_ctx
, blob
, req
->body
.data
,
1027 req
->body
.length
)) {
1028 return NT_STATUS_NO_MEMORY
;
1032 return NT_STATUS_OK
;
1035 struct http_send_request_state
{
1036 struct tevent_context
*ev
;
1037 struct loadparm_context
*lp_ctx
;
1038 struct cli_credentials
*credentials
;
1039 struct http_request
*request
;
1047 * Sends and HTTP request
1049 static void http_send_request_done(struct tevent_req
*);
1050 struct tevent_req
*http_send_request_send(TALLOC_CTX
*mem_ctx
,
1051 struct tevent_context
*ev
,
1052 struct http_conn
*http_conn
,
1053 struct http_request
*request
)
1055 struct tevent_req
*req
;
1056 struct tevent_req
*subreq
;
1057 struct http_send_request_state
*state
= NULL
;
1060 DEBUG(11, ("%s: Sending HTTP request\n", __func__
));
1063 if (ev
== NULL
|| request
== NULL
|| http_conn
== NULL
) {
1064 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
1068 req
= tevent_req_create(mem_ctx
, &state
, struct http_send_request_state
);
1074 state
->request
= request
;
1076 /* Push the request line */
1077 status
= http_push_request_line(state
, &state
->buffer
, state
->request
);
1078 if (!NT_STATUS_IS_OK(status
)) {
1079 tevent_req_nterror(req
, status
);
1080 return tevent_req_post(req
, ev
);
1083 /* Push the headers */
1084 status
= http_push_headers(mem_ctx
, &state
->buffer
, request
);
1085 if (!NT_STATUS_IS_OK(status
)) {
1086 tevent_req_nterror(req
, status
);
1087 return tevent_req_post(req
, ev
);
1091 status
= http_push_body(mem_ctx
, &state
->buffer
, request
);
1092 if (!NT_STATUS_IS_OK(status
)) {
1093 tevent_req_nterror(req
, status
);
1094 return tevent_req_post(req
, ev
);
1097 state
->iov
.iov_base
= (char *) state
->buffer
.data
;
1098 state
->iov
.iov_len
= state
->buffer
.length
;
1099 subreq
= tstream_writev_queue_send(state
,
1101 http_conn
->tstreams
.active
,
1102 http_conn
->send_queue
,
1104 if (tevent_req_nomem(subreq
, req
)) {
1105 return tevent_req_post(req
, ev
);
1107 tevent_req_set_callback(subreq
, http_send_request_done
, req
);
1112 static void http_send_request_done(struct tevent_req
*subreq
)
1115 struct tevent_req
*req
;
1116 struct http_send_request_state
*state
;
1118 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
1119 state
= tevent_req_data(req
, struct http_send_request_state
);
1121 state
->nwritten
= tstream_writev_queue_recv(subreq
, &state
->sys_errno
);
1122 TALLOC_FREE(subreq
);
1123 if (state
->nwritten
== -1 && state
->sys_errno
!= 0) {
1124 status
= map_nt_error_from_unix_common(state
->sys_errno
);
1125 DEBUG(0, ("%s: Failed to send HTTP request: %s\n",
1126 __func__
, nt_errstr(status
)));
1127 tevent_req_nterror(req
, status
);
1131 tevent_req_done(req
);
1134 NTSTATUS
http_send_request_recv(struct tevent_req
*req
)
1139 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
1140 return NT_STATUS_INVALID_PARAMETER
;
1143 if (tevent_req_is_nterror(req
, &status
)) {
1144 tevent_req_received(req
);
1148 tevent_req_received(req
);
1150 return NT_STATUS_OK
;