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"
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.
35 static int http_response_needs_body(struct http_request
*req
)
37 struct http_header
*h
= NULL
;
41 for (h
= req
->headers
; h
!= NULL
; h
= h
->next
) {
47 cmp
= strcasecmp(h
->key
, "Content-Length");
52 n
= sscanf(h
->value
, "%llu%c", &v
, &c
);
57 req
->remaining_content_length
= v
;
69 struct http_read_response_state
{
70 enum http_parser_state parser_state
;
71 size_t max_headers_size
;
72 uint64_t max_content_length
;
74 struct http_request
*response
;
78 * Parses the HTTP headers
80 static enum http_read_status
http_parse_headers(struct http_read_response_state
*state
)
82 enum http_read_status status
= HTTP_ALL_DATA_READ
;
91 if (!state
|| !state
->response
) {
92 DEBUG(0, ("%s: Invalid Parameter\n", __func__
));
93 return HTTP_DATA_CORRUPTED
;
96 if (state
->buffer
.length
> state
->max_headers_size
) {
97 DEBUG(0, ("%s: Headers too long: %zi, maximum length is %zi\n", __func__
,
98 state
->buffer
.length
, state
->max_headers_size
));
99 return HTTP_DATA_TOO_LONG
;
102 line
= talloc_strndup(state
, (char *)state
->buffer
.data
, state
->buffer
.length
);
104 DEBUG(0, ("%s: Memory error\n", __func__
));
105 return HTTP_DATA_CORRUPTED
;
108 ptr
= strstr(line
, "\r\n");
111 return HTTP_MORE_DATA_EXPECTED
;
114 state
->response
->headers_size
+= state
->buffer
.length
;
116 if (strncmp(line
, "\r\n", 2) == 0) {
117 DEBUG(11,("%s: All headers read\n", __func__
));
119 ret
= http_response_needs_body(state
->response
);
122 if (state
->response
->remaining_content_length
<= state
->max_content_length
) {
123 DEBUG(11, ("%s: Start of read body\n", __func__
));
124 state
->parser_state
= HTTP_READING_BODY
;
129 DEBUG(11, ("%s: Skipping body for code %d\n", __func__
,
130 state
->response
->response_code
));
131 state
->parser_state
= HTTP_READING_DONE
;
134 DEBUG(0, ("%s_: Error in http_response_needs_body\n", __func__
));
136 return HTTP_DATA_CORRUPTED
;
141 return HTTP_ALL_DATA_READ
;
144 n
= sscanf(line
, "%m[^:]: %m[^\r\n]\r\n", &key
, &value
);
146 DEBUG(0, ("%s: Error parsing header '%s'\n", __func__
, line
));
147 status
= HTTP_DATA_CORRUPTED
;
151 if (http_add_header(state
->response
, &state
->response
->headers
, key
, value
) == -1) {
152 DEBUG(0, ("%s: Error adding header\n", __func__
));
153 status
= HTTP_DATA_CORRUPTED
;
165 * Parses the first line of a HTTP response
167 static bool http_parse_response_line(struct http_read_response_state
*state
)
180 DEBUG(0, ("%s: Input parameter is NULL\n", __func__
));
184 line
= talloc_strndup(state
, (char*)state
->buffer
.data
, state
->buffer
.length
);
186 DEBUG(0, ("%s: Memory error\n", __func__
));
190 n
= sscanf(line
, "%m[^/]/%c.%c %d %m[^\r\n]\r\n",
191 &protocol
, &major
, &minor
, &code
, &msg
);
193 DEBUG(11, ("%s: Header parsed(%i): protocol->%s, major->%c, minor->%c, "
194 "code->%d, message->%s\n", __func__
, n
, protocol
, major
, minor
,
198 DEBUG(0, ("%s: Error parsing header\n", __func__
));
204 DEBUG(0, ("%s: Bad HTTP major number '%c'\n", __func__
, major
));
210 DEBUG(0, ("%s: Bad response code '%d'", __func__
, code
));
216 DEBUG(0, ("%s: Error parsing HTTP data\n", __func__
));
221 state
->response
->major
= major
;
222 state
->response
->minor
= minor
;
223 state
->response
->response_code
= code
;
224 state
->response
->response_code_line
= talloc_strndup(state
->response
,
235 * Parses header lines from a request or a response into the specified
236 * request object given a buffer.
239 * HTTP_DATA_CORRUPTED on error
240 * HTTP_MORE_DATA_EXPECTED when we need to read more headers
241 * HTTP_DATA_TOO_LONG on error
242 * HTTP_ALL_DATA_READ when all headers have been read
244 static enum http_read_status
http_parse_firstline(struct http_read_response_state
*state
)
246 enum http_read_status status
= HTTP_ALL_DATA_READ
;
252 DEBUG(0, ("%s: Invalid Parameter\n", __func__
));
253 return HTTP_DATA_CORRUPTED
;
256 if (state
->buffer
.length
> state
->max_headers_size
) {
257 DEBUG(0, ("%s: Headers too long: %zi, maximum length is %zi\n", __func__
,
258 state
->buffer
.length
, state
->max_headers_size
));
259 return HTTP_DATA_TOO_LONG
;
262 line
= talloc_strndup(state
, (char *)state
->buffer
.data
, state
->buffer
.length
);
264 DEBUG(0, ("%s: Not enough memory\n", __func__
));
265 return HTTP_DATA_CORRUPTED
;
268 ptr
= strstr(line
, "\r\n");
271 return HTTP_MORE_DATA_EXPECTED
;
274 state
->response
->headers_size
= state
->buffer
.length
;
275 if (!http_parse_response_line(state
)) {
276 status
= HTTP_DATA_CORRUPTED
;
279 /* Next state, read HTTP headers */
280 state
->parser_state
= HTTP_READING_HEADERS
;
286 static enum http_read_status
http_read_body(struct http_read_response_state
*state
)
288 struct http_request
*resp
= state
->response
;
290 if (state
->buffer
.length
< resp
->remaining_content_length
) {
291 return HTTP_MORE_DATA_EXPECTED
;
294 resp
->body
= state
->buffer
;
295 state
->buffer
= data_blob_null
;
296 talloc_steal(resp
, resp
->body
.data
);
297 resp
->remaining_content_length
= 0;
299 state
->parser_state
= HTTP_READING_DONE
;
300 return HTTP_ALL_DATA_READ
;
303 static enum http_read_status
http_read_trailer(struct http_read_response_state
*state
)
305 enum http_read_status status
= HTTP_DATA_CORRUPTED
;
310 static enum http_read_status
http_parse_buffer(struct http_read_response_state
*state
)
313 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
314 return HTTP_DATA_CORRUPTED
;
317 switch (state
->parser_state
) {
318 case HTTP_READING_FIRSTLINE
:
319 return http_parse_firstline(state
);
320 case HTTP_READING_HEADERS
:
321 return http_parse_headers(state
);
322 case HTTP_READING_BODY
:
323 return http_read_body(state
);
325 case HTTP_READING_TRAILER
:
326 return http_read_trailer(state
);
328 case HTTP_READING_DONE
:
330 return HTTP_ALL_DATA_READ
;
332 DEBUG(0, ("%s: Illegal parser state %d", __func__
,
333 state
->parser_state
));
336 return HTTP_DATA_CORRUPTED
;
339 static int http_header_is_valid_value(const char *value
)
341 const char *p
= NULL
;
345 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
350 while ((p
= strpbrk(p
, "\r\n")) != NULL
) {
351 /* Expect only one new line */
352 p
+= strspn(p
, "\r\n");
353 /* Expect a space or tab for continuation */
354 if (*p
!= ' ' && *p
!= '\t')
360 static int http_add_header_internal(TALLOC_CTX
*mem_ctx
,
361 struct http_header
**headers
,
362 const char *key
, const char *value
,
365 struct http_header
*tail
= NULL
;
366 struct http_header
*h
= NULL
;
369 if (!headers
|| !key
|| !value
) {
370 DEBUG(0, ("Invalid parameter\n"));
377 for (h
= *headers
; h
!= NULL
; h
= h
->next
) {
378 if (strcasecmp(key
, h
->key
) == 0) {
384 /* Replace header value */
386 talloc_free(h
->value
);
388 h
->value
= talloc_strdup(h
, value
);
389 DEBUG(11, ("%s: Replaced HTTP header: key '%s', value '%s'\n",
390 __func__
, h
->key
, h
->value
));
396 h
= talloc(mem_ctx
, struct http_header
);
397 h
->key
= talloc_strdup(h
, key
);
398 h
->value
= talloc_strdup(h
, value
);
399 DLIST_ADD_END(*headers
, h
);
400 tail
= DLIST_TAIL(*headers
);
402 DEBUG(0, ("%s: Error adding header\n", __func__
));
405 DEBUG(11, ("%s: Added HTTP header: key '%s', value '%s'\n",
406 __func__
, h
->key
, h
->value
));
410 int http_add_header(TALLOC_CTX
*mem_ctx
,
411 struct http_header
**headers
,
412 const char *key
, const char *value
)
414 if (strchr(key
, '\r') != NULL
|| strchr(key
, '\n') != NULL
) {
415 DEBUG(0, ("%s: Dropping illegal header key\n", __func__
));
419 if (!http_header_is_valid_value(value
)) {
420 DEBUG(0, ("%s: Dropping illegal header value\n", __func__
));
424 return (http_add_header_internal(mem_ctx
, headers
, key
, value
, false));
427 int http_replace_header(TALLOC_CTX
*mem_ctx
,
428 struct http_header
**headers
,
429 const char *key
, const char *value
)
431 if (strchr(key
, '\r') != NULL
|| strchr(key
, '\n') != NULL
) {
432 DEBUG(0, ("%s: Dropping illegal header key\n", __func__
));
436 if (!http_header_is_valid_value(value
)) {
437 DEBUG(0, ("%s: Dropping illegal header value\n", __func__
));
441 return (http_add_header_internal(mem_ctx
, headers
, key
, value
, true));
445 * Remove a header from the headers list.
447 * Returns 0, if the header was successfully removed.
448 * Returns -1, if the header could not be found.
450 int http_remove_header(struct http_header
**headers
, const char *key
)
452 struct http_header
*header
;
455 if (!headers
|| !key
) {
456 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
460 for(header
= *headers
; header
!= NULL
; header
= header
->next
) {
461 if (strcmp(key
, header
->key
) == 0) {
462 DLIST_REMOVE(*headers
, header
);
469 static int http_read_response_next_vector(struct tstream_context
*stream
,
472 struct iovec
**_vector
,
475 struct http_read_response_state
*state
;
476 struct iovec
*vector
;
479 if (!stream
|| !private_data
|| !_vector
|| !_count
) {
480 DEBUG(0, ("%s: Invalid Parameter\n", __func__
));
484 state
= talloc_get_type_abort(private_data
, struct http_read_response_state
);
485 vector
= talloc_array(mem_ctx
, struct iovec
, 1);
487 DEBUG(0, ("%s: No more memory\n", __func__
));
491 if (state
->buffer
.data
== NULL
) {
492 /* Allocate buffer */
493 state
->buffer
.data
= talloc_zero_array(state
, uint8_t, 1);
494 if (!state
->buffer
.data
) {
495 DEBUG(0, ("%s: No more memory\n", __func__
));
498 state
->buffer
.length
= 1;
500 /* Return now, nothing to parse yet */
501 vector
[0].iov_base
= (void *)(state
->buffer
.data
);
502 vector
[0].iov_len
= 1;
508 switch (http_parse_buffer(state
)) {
509 case HTTP_ALL_DATA_READ
:
510 if (state
->parser_state
== HTTP_READING_DONE
) {
511 /* Full request or response parsed */
515 /* Free current buffer and allocate new one */
516 TALLOC_FREE(state
->buffer
.data
);
517 state
->buffer
.data
= talloc_zero_array(state
, uint8_t, 1);
518 if (!state
->buffer
.data
) {
521 state
->buffer
.length
= 1;
523 vector
[0].iov_base
= (void *)(state
->buffer
.data
);
524 vector
[0].iov_len
= 1;
529 case HTTP_MORE_DATA_EXPECTED
:
530 /* TODO Optimize, allocating byte by byte */
531 state
->buffer
.data
= talloc_realloc(state
, state
->buffer
.data
,
532 uint8_t, state
->buffer
.length
+ 1);
533 if (!state
->buffer
.data
) {
536 state
->buffer
.length
++;
537 vector
[0].iov_base
= (void *)(state
->buffer
.data
+
538 state
->buffer
.length
- 1);
539 vector
[0].iov_len
= 1;
543 case HTTP_DATA_CORRUPTED
:
544 case HTTP_REQUEST_CANCELED
:
545 case HTTP_DATA_TOO_LONG
:
549 DEBUG(0, ("%s: Unexpected status\n", __func__
));
557 * Reads a HTTP response
559 static void http_read_response_done(struct tevent_req
*);
560 struct tevent_req
*http_read_response_send(TALLOC_CTX
*mem_ctx
,
561 struct tevent_context
*ev
,
562 struct http_conn
*http_conn
,
563 size_t max_content_length
)
565 struct tevent_req
*req
;
566 struct tevent_req
*subreq
;
567 struct http_read_response_state
*state
;
569 DEBUG(11, ("%s: Reading HTTP response\n", __func__
));
572 if (ev
== NULL
|| http_conn
== NULL
) {
573 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
577 req
= tevent_req_create(mem_ctx
, &state
, struct http_read_response_state
);
582 state
->max_headers_size
= HTTP_MAX_HEADER_SIZE
;
583 state
->max_content_length
= (uint64_t)max_content_length
;
584 state
->parser_state
= HTTP_READING_FIRSTLINE
;
585 state
->response
= talloc_zero(state
, struct http_request
);
586 if (tevent_req_nomem(state
->response
, req
)) {
587 return tevent_req_post(req
, ev
);
590 subreq
= tstream_readv_pdu_send(state
, ev
, http_conn
->tstreams
.active
,
591 http_read_response_next_vector
,
593 if (tevent_req_nomem(subreq
,req
)) {
594 return tevent_req_post(req
, ev
);
596 tevent_req_set_callback(subreq
, http_read_response_done
, req
);
601 static void http_read_response_done(struct tevent_req
*subreq
)
604 struct tevent_req
*req
;
609 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
613 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
615 ret
= tstream_readv_pdu_recv(subreq
, &sys_errno
);
616 DEBUG(11, ("%s: HTTP response read (%d bytes)\n", __func__
, ret
));
619 status
= map_nt_error_from_unix_common(sys_errno
);
620 DEBUG(0, ("%s: Failed to read HTTP response: %s\n",
621 __func__
, nt_errstr(status
)));
622 tevent_req_nterror(req
, status
);
626 tevent_req_done(req
);
629 NTSTATUS
http_read_response_recv(struct tevent_req
*req
,
631 struct http_request
**response
)
634 struct http_read_response_state
*state
;
636 if (!mem_ctx
|| !response
|| !req
) {
637 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
638 return NT_STATUS_INVALID_PARAMETER
;
640 if (tevent_req_is_nterror(req
, &status
)) {
641 tevent_req_received(req
);
645 state
= tevent_req_data(req
, struct http_read_response_state
);
646 *response
= state
->response
;
647 talloc_steal(mem_ctx
, state
->response
);
649 tevent_req_received(req
);
654 static const char *http_method_str(enum http_cmd_type type
)
662 case HTTP_REQ_RPC_IN_DATA
:
663 method
= "RPC_IN_DATA";
665 case HTTP_REQ_RPC_OUT_DATA
:
666 method
= "RPC_OUT_DATA";
676 static NTSTATUS
http_push_request_line(TALLOC_CTX
*mem_ctx
,
678 const struct http_request
*req
)
684 if (!buffer
|| !req
) {
685 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
686 return NT_STATUS_INVALID_PARAMETER
;
689 method
= http_method_str(req
->type
);
690 if (method
== NULL
) {
691 return NT_STATUS_INVALID_PARAMETER
;
694 str
= talloc_asprintf(mem_ctx
, "%s %s HTTP/%c.%c\r\n", method
,
695 req
->uri
, req
->major
, req
->minor
);
697 return NT_STATUS_NO_MEMORY
;
699 if (!data_blob_append(mem_ctx
, buffer
, str
, strlen(str
))) {
701 return NT_STATUS_NO_MEMORY
;
708 static NTSTATUS
http_push_headers(TALLOC_CTX
*mem_ctx
,
710 struct http_request
*req
)
712 struct http_header
*header
= NULL
;
713 char *header_str
= NULL
;
718 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
719 return NT_STATUS_INVALID_PARAMETER
;
722 for (header
= req
->headers
; header
!= NULL
; header
= header
->next
) {
723 header_str
= talloc_asprintf(mem_ctx
, "%s: %s\r\n",
724 header
->key
, header
->value
);
725 if (header_str
== NULL
) {
726 return NT_STATUS_NO_MEMORY
;
729 len
= strlen(header_str
);
730 if (!data_blob_append(mem_ctx
, blob
, header_str
, len
)) {
731 talloc_free(header_str
);
732 return NT_STATUS_NO_MEMORY
;
734 talloc_free(header_str
);
737 if (!data_blob_append(mem_ctx
, blob
, "\r\n",2)) {
738 return NT_STATUS_NO_MEMORY
;
745 static NTSTATUS
http_push_body(TALLOC_CTX
*mem_ctx
,
747 struct http_request
*req
)
751 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
752 return NT_STATUS_INVALID_PARAMETER
;
755 if (req
->body
.length
) {
756 if (!data_blob_append(mem_ctx
, blob
, req
->body
.data
,
758 return NT_STATUS_NO_MEMORY
;
765 struct http_send_request_state
{
766 struct tevent_context
*ev
;
767 struct loadparm_context
*lp_ctx
;
768 struct cli_credentials
*credentials
;
769 struct http_request
*request
;
777 * Sends and HTTP request
779 static void http_send_request_done(struct tevent_req
*);
780 struct tevent_req
*http_send_request_send(TALLOC_CTX
*mem_ctx
,
781 struct tevent_context
*ev
,
782 struct http_conn
*http_conn
,
783 struct http_request
*request
)
785 struct tevent_req
*req
;
786 struct tevent_req
*subreq
;
787 struct http_send_request_state
*state
= NULL
;
790 DEBUG(11, ("%s: Sending HTTP request\n", __func__
));
793 if (ev
== NULL
|| request
== NULL
|| http_conn
== NULL
) {
794 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
798 req
= tevent_req_create(mem_ctx
, &state
, struct http_send_request_state
);
804 state
->request
= request
;
806 /* Push the request line */
807 status
= http_push_request_line(state
, &state
->buffer
, state
->request
);
808 if (!NT_STATUS_IS_OK(status
)) {
809 tevent_req_nterror(req
, status
);
810 return tevent_req_post(req
, ev
);
813 /* Push the headers */
814 status
= http_push_headers(mem_ctx
, &state
->buffer
, request
);
815 if (!NT_STATUS_IS_OK(status
)) {
816 tevent_req_nterror(req
, status
);
817 return tevent_req_post(req
, ev
);
821 status
= http_push_body(mem_ctx
, &state
->buffer
, request
);
822 if (!NT_STATUS_IS_OK(status
)) {
823 tevent_req_nterror(req
, status
);
824 return tevent_req_post(req
, ev
);
827 state
->iov
.iov_base
= (char *) state
->buffer
.data
;
828 state
->iov
.iov_len
= state
->buffer
.length
;
829 subreq
= tstream_writev_queue_send(state
,
831 http_conn
->tstreams
.active
,
832 http_conn
->send_queue
,
834 if (tevent_req_nomem(subreq
, req
)) {
835 return tevent_req_post(req
, ev
);
837 tevent_req_set_callback(subreq
, http_send_request_done
, req
);
842 static void http_send_request_done(struct tevent_req
*subreq
)
845 struct tevent_req
*req
;
846 struct http_send_request_state
*state
;
848 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
849 state
= tevent_req_data(req
, struct http_send_request_state
);
851 state
->nwritten
= tstream_writev_queue_recv(subreq
, &state
->sys_errno
);
853 if (state
->nwritten
== -1 && state
->sys_errno
!= 0) {
854 status
= map_nt_error_from_unix_common(state
->sys_errno
);
855 DEBUG(0, ("%s: Failed to send HTTP request: %s\n",
856 __func__
, nt_errstr(status
)));
857 tevent_req_nterror(req
, status
);
861 tevent_req_done(req
);
864 NTSTATUS
http_send_request_recv(struct tevent_req
*req
)
869 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
870 return NT_STATUS_INVALID_PARAMETER
;
873 if (tevent_req_is_nterror(req
, &status
)) {
874 tevent_req_received(req
);
878 tevent_req_received(req
);