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 <talloc_dict.h>
24 #include "lib/util/tevent_ntstatus.h"
26 #include "http_internal.h"
27 #include "util/tevent_werror.h"
28 #include "lib/util/dlinklist.h"
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.
37 static int http_response_needs_body(struct http_request
*req
)
41 /* If response code is 503, the body contains the error description
44 if (req
->response_code
== 503)
52 * Parses the HTTP headers
54 static enum http_read_status
http_parse_headers(struct http_read_response_state
*state
)
56 enum http_read_status status
= HTTP_ALL_DATA_READ
;
65 if (!state
|| !state
->response
) {
66 DEBUG(0, ("%s: Invalid Parameter\n", __func__
));
67 return HTTP_DATA_CORRUPTED
;
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
;
76 line
= talloc_strndup(state
, (char *)state
->buffer
.data
, state
->buffer
.length
);
78 DEBUG(0, ("%s: Memory error\n", __func__
));
79 return HTTP_DATA_CORRUPTED
;
82 ptr
= strstr(line
, "\r\n");
85 return HTTP_MORE_DATA_EXPECTED
;
88 state
->response
->headers_size
+= state
->buffer
.length
;
90 if (strncmp(line
, "\r\n", 2) == 0) {
91 DEBUG(11,("%s: All headers read\n", __func__
));
93 ret
= http_response_needs_body(state
->response
);
96 DEBUG(11, ("%s: Skipping body for code %d\n", __func__
,
97 state
->response
->response_code
));
98 state
->parser_state
= HTTP_READING_DONE
;
101 DEBUG(11, ("%s: Start of read body\n", __func__
));
102 state
->parser_state
= HTTP_READING_BODY
;
105 DEBUG(0, ("%s_: Error in http_response_needs_body\n", __func__
));
107 return HTTP_DATA_CORRUPTED
;
112 return HTTP_ALL_DATA_READ
;
115 n
= sscanf(line
, "%m[^:]: %m[^\r\n]\r\n", &key
, &value
);
117 DEBUG(0, ("%s: Error parsing header '%s'\n", __func__
, line
));
118 status
= HTTP_DATA_CORRUPTED
;
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
;
136 * Parses the first line of a HTTP response
138 static bool http_parse_response_line(struct http_read_response_state
*state
)
151 DEBUG(0, ("%s: Input parameter is NULL\n", __func__
));
155 line
= talloc_strndup(state
, (char*)state
->buffer
.data
, state
->buffer
.length
);
157 DEBUG(0, ("%s: Memory error\n", __func__
));
161 n
= sscanf(line
, "%m[^/]/%c.%c %d %m[^\r\n]\r\n",
162 &protocol
, &major
, &minor
, &code
, &msg
);
164 DEBUG(11, ("%s: Header parsed(%i): protocol->%s, major->%c, minor->%c, "
165 "code->%d, message->%s\n", __func__
, n
, protocol
, major
, minor
,
169 DEBUG(0, ("%s: Error parsing header\n", __func__
));
175 DEBUG(0, ("%s: Bad HTTP major number '%c'\n", __func__
, major
));
181 DEBUG(0, ("%s: Bad response code '%d'", __func__
, code
));
187 DEBUG(0, ("%s: Error parsing HTTP data\n", __func__
));
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
,
206 * Parses header lines from a request or a response into the specified
207 * request object given a buffer.
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
215 static enum http_read_status
http_parse_firstline(struct http_read_response_state
*state
)
217 enum http_read_status status
= HTTP_ALL_DATA_READ
;
223 DEBUG(0, ("%s: Invalid Parameter\n", __func__
));
224 return HTTP_DATA_CORRUPTED
;
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
;
233 line
= talloc_strndup(state
, (char *)state
->buffer
.data
, state
->buffer
.length
);
235 DEBUG(0, ("%s: Not enough memory\n", __func__
));
236 return HTTP_DATA_CORRUPTED
;
239 ptr
= strstr(line
, "\r\n");
242 return HTTP_MORE_DATA_EXPECTED
;
245 state
->response
->headers_size
= state
->buffer
.length
;
246 if (!http_parse_response_line(state
)) {
247 status
= HTTP_DATA_CORRUPTED
;
250 /* Next state, read HTTP headers */
251 state
->parser_state
= HTTP_READING_HEADERS
;
257 static enum http_read_status
http_read_body(struct http_read_response_state
*state
)
259 enum http_read_status status
= HTTP_DATA_CORRUPTED
;
264 static enum http_read_status
http_read_trailer(struct http_read_response_state
*state
)
266 enum http_read_status status
= HTTP_DATA_CORRUPTED
;
271 static enum http_read_status
http_parse_buffer(struct http_read_response_state
*state
)
274 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
275 return HTTP_DATA_CORRUPTED
;
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
);
286 case HTTP_READING_TRAILER
:
287 return http_read_trailer(state
);
289 case HTTP_READING_DONE
:
291 return HTTP_ALL_DATA_READ
;
293 DEBUG(0, ("%s: Illegal parser state %d", __func__
,
294 state
->parser_state
));
297 return HTTP_DATA_CORRUPTED
;
300 static int http_header_is_valid_value(const char *value
)
302 const char *p
= NULL
;
306 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
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')
321 static int http_add_header_internal(TALLOC_CTX
*mem_ctx
,
322 struct http_header
**headers
,
323 const char *key
, const char *value
,
326 struct http_header
*tail
= NULL
;
327 struct http_header
*h
= NULL
;
330 if (!headers
|| !key
|| !value
) {
331 DEBUG(0, ("Invalid parameter\n"));
338 for (h
= *headers
; h
!= NULL
; h
= h
->next
) {
339 if (strcasecmp(key
, h
->key
) == 0) {
345 /* Replace header value */
347 talloc_free(h
->value
);
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
));
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
, NULL
);
361 tail
= DLIST_TAIL(*headers
);
363 DEBUG(0, ("%s: Error adding header\n", __func__
));
366 DEBUG(11, ("%s: Added HTTP header: key '%s', value '%s'\n",
367 __func__
, h
->key
, h
->value
));
371 int http_add_header(TALLOC_CTX
*mem_ctx
,
372 struct http_header
**headers
,
373 const char *key
, const char *value
)
375 if (strchr(key
, '\r') != NULL
|| strchr(key
, '\n') != NULL
) {
376 DEBUG(0, ("%s: Dropping illegal header key\n", __func__
));
380 if (!http_header_is_valid_value(value
)) {
381 DEBUG(0, ("%s: Dropping illegal header value\n", __func__
));
385 return (http_add_header_internal(mem_ctx
, headers
, key
, value
, false));
388 int http_replace_header(TALLOC_CTX
*mem_ctx
,
389 struct http_header
**headers
,
390 const char *key
, const char *value
)
392 if (strchr(key
, '\r') != NULL
|| strchr(key
, '\n') != NULL
) {
393 DEBUG(0, ("%s: Dropping illegal header key\n", __func__
));
397 if (!http_header_is_valid_value(value
)) {
398 DEBUG(0, ("%s: Dropping illegal header value\n", __func__
));
402 return (http_add_header_internal(mem_ctx
, headers
, key
, value
, true));
406 * Remove a header from the headers list.
408 * Returns 0, if the header was successfully removed.
409 * Returns -1, if the header could not be found.
411 int http_remove_header(struct http_header
**headers
, const char *key
)
413 struct http_header
*header
;
416 if (!headers
|| !key
) {
417 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
421 for(header
= *headers
; header
!= NULL
; header
= header
->next
) {
422 if (strcmp(key
, header
->key
) == 0) {
423 DLIST_REMOVE(*headers
, header
);
430 static int http_read_response_next_vector(struct tstream_context
*stream
,
433 struct iovec
**_vector
,
436 struct http_read_response_state
*state
;
437 struct iovec
*vector
;
440 if (!stream
|| !private_data
|| !_vector
|| !_count
) {
441 DEBUG(0, ("%s: Invalid Parameter\n", __func__
));
444 state
= talloc_get_type_abort(private_data
, struct http_read_response_state
);
445 vector
= talloc_array(mem_ctx
, struct iovec
, 1);
447 DEBUG(0, ("%s: No more memory\n", __func__
));
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__
));
458 state
->buffer
.length
= 1;
460 /* Return now, nothing to parse yet */
461 vector
[0].iov_base
= (void *)(state
->buffer
.data
);
462 vector
[0].iov_len
= 1;
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 */
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
) {
481 state
->buffer
.length
= 1;
483 vector
[0].iov_base
= (void *)(state
->buffer
.data
);
484 vector
[0].iov_len
= 1;
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
) {
496 state
->buffer
.length
++;
497 vector
[0].iov_base
= (void *)(state
->buffer
.data
+
498 state
->buffer
.length
- 1);
499 vector
[0].iov_len
= 1;
503 case HTTP_DATA_CORRUPTED
:
504 case HTTP_REQUEST_CANCELED
:
505 case HTTP_DATA_TOO_LONG
:
509 DEBUG(0, ("%s: Unexpected status\n", __func__
));
517 * Reads a HTTP response
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
)
524 struct tevent_req
*req
;
525 struct tevent_req
*subreq
;
526 struct http_read_response_state
*state
;
528 DEBUG(11, ("%s: Reading HTTP response\n", __func__
));
531 if (!ev
|| !stream
) {
532 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
536 req
= tevent_req_create(mem_ctx
, &state
, struct http_read_response_state
);
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
);
548 subreq
= tstream_readv_pdu_send(state
, ev
, stream
,
549 http_read_response_next_vector
,
551 if (tevent_req_nomem(subreq
,req
)) {
552 return tevent_req_post(req
, ev
);
554 tevent_req_set_callback(subreq
, http_read_response_done
, req
);
559 static void http_read_response_done(struct tevent_req
*subreq
)
562 struct tevent_req
*req
;
567 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
571 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
573 ret
= tstream_readv_pdu_recv(subreq
, &sys_errno
);
574 DEBUG(11, ("%s: HTTP response read (%d bytes)\n", __func__
, ret
));
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
);
584 tevent_req_done(req
);
587 NTSTATUS
http_read_response_recv(struct tevent_req
*req
,
589 struct http_request
**response
)
592 struct http_read_response_state
*state
;
594 if (!mem_ctx
|| !response
|| !req
) {
595 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
596 return NT_STATUS_INVALID_PARAMETER
;
598 if (tevent_req_is_nterror(req
, &status
)) {
599 tevent_req_received(req
);
603 state
= tevent_req_data(req
, struct http_read_response_state
);
604 *response
= state
->response
;
605 talloc_steal(mem_ctx
, state
->response
);
607 tevent_req_received(req
);
612 static const char *http_method_str(enum http_cmd_type type
)
617 case HTTP_REQ_RPC_IN_DATA
:
618 method
= "RPC_IN_DATA";
620 case HTTP_REQ_RPC_OUT_DATA
:
621 method
= "RPC_OUT_DATA";
631 static NTSTATUS
http_push_request_line(TALLOC_CTX
*mem_ctx
,
633 const struct http_request
*req
)
639 if (!buffer
|| !req
) {
640 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
641 return NT_STATUS_INVALID_PARAMETER
;
644 method
= http_method_str(req
->type
);
645 if (method
== NULL
) {
646 return NT_STATUS_INVALID_PARAMETER
;
649 str
= talloc_asprintf(mem_ctx
, "%s %s HTTP/%c.%c\r\n", method
,
650 req
->uri
, req
->major
, req
->minor
);
652 return NT_STATUS_NO_MEMORY
;
654 if (!data_blob_append(mem_ctx
, buffer
, str
, strlen(str
))) {
656 return NT_STATUS_NO_MEMORY
;
663 static NTSTATUS
http_push_headers(TALLOC_CTX
*mem_ctx
,
665 struct http_request
*req
)
667 struct http_header
*header
= NULL
;
668 char *header_str
= NULL
;
673 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
674 return NT_STATUS_INVALID_PARAMETER
;
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
;
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
;
689 talloc_free(header_str
);
692 if (!data_blob_append(mem_ctx
, blob
, "\r\n",2)) {
693 return NT_STATUS_NO_MEMORY
;
700 static NTSTATUS
http_push_body(TALLOC_CTX
*mem_ctx
,
702 struct http_request
*req
)
706 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
707 return NT_STATUS_INVALID_PARAMETER
;
710 if (req
->body
.length
) {
711 if (!data_blob_append(mem_ctx
, blob
, req
->body
.data
,
713 return NT_STATUS_NO_MEMORY
;
721 * Sends and HTTP request
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
)
730 struct tevent_req
*req
;
731 struct tevent_req
*subreq
;
732 struct http_send_request_state
*state
= NULL
;
735 DEBUG(11, ("%s: Sending HTTP request\n", __func__
));
738 if (!ev
|| !stream
|| !send_queue
|| !request
) {
739 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
743 req
= tevent_req_create(mem_ctx
, &state
, struct http_send_request_state
);
749 state
->stream
= stream
;
750 state
->send_queue
= send_queue
;
751 state
->request
= request
;
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
);
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
);
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
);
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
,
778 if (tevent_req_nomem(subreq
, req
)) {
779 return tevent_req_post(req
, ev
);
781 tevent_req_set_callback(subreq
, http_send_request_done
, req
);
786 static void http_send_request_done(struct tevent_req
*subreq
)
789 struct tevent_req
*req
;
790 struct http_send_request_state
*state
;
792 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
793 state
= tevent_req_data(req
, struct http_send_request_state
);
795 state
->nwritten
= tstream_writev_queue_recv(subreq
, &state
->sys_errno
);
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
);
805 tevent_req_done(req
);
808 NTSTATUS
http_send_request_recv(struct tevent_req
*req
)
813 DEBUG(0, ("%s: Invalid parameter\n", __func__
));
814 return NT_STATUS_INVALID_PARAMETER
;
817 if (tevent_req_is_nterror(req
, &status
)) {
818 tevent_req_received(req
);
822 tevent_req_received(req
);