1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
25 #ifndef CURL_DISABLE_HTTP
27 #ifdef HAVE_SYS_SOCKET_H
28 #include <sys/socket.h>
30 #ifdef HAVE_NETINET_IN_H
31 #include <netinet/in.h>
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
46 #ifdef HAVE_SYS_IOCTL_H
47 #include <sys/ioctl.h>
50 #ifdef HAVE_SYS_PARAM_H
51 #include <sys/param.h>
55 #include <curl/curl.h>
60 #include "curl_base64.h"
64 #include "http_digest.h"
65 #include "curl_ntlm.h"
66 #include "curl_ntlm_wb.h"
67 #include "http_negotiate.h"
72 #include "curl_memory.h"
74 #include "parsedate.h" /* for the week day and month names */
75 #include "strtoofft.h"
78 #include "content_encoding.h"
79 #include "http_proxy.h"
81 #include "non-ascii.h"
83 #define _MPRINTF_REPLACE /* use our functions only */
84 #include <curl/mprintf.h>
86 /* The last #include file should be: */
90 * Forward declarations.
93 static int http_getsock_do(struct connectdata *conn,
96 static int http_should_fail(struct connectdata *conn);
99 static CURLcode https_connecting(struct connectdata *conn, bool *done);
100 static int https_getsock(struct connectdata *conn,
101 curl_socket_t *socks,
104 #define https_connecting(x,y) CURLE_COULDNT_CONNECT
108 * HTTP handler interface.
110 const struct Curl_handler Curl_handler_http = {
112 ZERO_NULL, /* setup_connection */
113 Curl_http, /* do_it */
114 Curl_http_done, /* done */
115 ZERO_NULL, /* do_more */
116 Curl_http_connect, /* connect_it */
117 ZERO_NULL, /* connecting */
118 ZERO_NULL, /* doing */
119 ZERO_NULL, /* proto_getsock */
120 http_getsock_do, /* doing_getsock */
121 ZERO_NULL, /* domore_getsock */
122 ZERO_NULL, /* perform_getsock */
123 ZERO_NULL, /* disconnect */
124 ZERO_NULL, /* readwrite */
125 PORT_HTTP, /* defport */
126 CURLPROTO_HTTP, /* protocol */
127 PROTOPT_NONE /* flags */
132 * HTTPS handler interface.
134 const struct Curl_handler Curl_handler_https = {
135 "HTTPS", /* scheme */
136 ZERO_NULL, /* setup_connection */
137 Curl_http, /* do_it */
138 Curl_http_done, /* done */
139 ZERO_NULL, /* do_more */
140 Curl_http_connect, /* connect_it */
141 https_connecting, /* connecting */
142 ZERO_NULL, /* doing */
143 https_getsock, /* proto_getsock */
144 http_getsock_do, /* doing_getsock */
145 ZERO_NULL, /* domore_getsock */
146 ZERO_NULL, /* perform_getsock */
147 ZERO_NULL, /* disconnect */
148 ZERO_NULL, /* readwrite */
149 PORT_HTTPS, /* defport */
150 CURLPROTO_HTTP | CURLPROTO_HTTPS, /* protocol */
151 PROTOPT_SSL /* flags */
157 * checkheaders() checks the linked list of custom HTTP headers for a
158 * particular header (prefix).
160 * Returns a pointer to the first matching header or NULL if none matched.
162 char *Curl_checkheaders(struct SessionHandle *data, const char *thisheader)
164 struct curl_slist *head;
165 size_t thislen = strlen(thisheader);
167 for(head = data->set.headers; head; head=head->next) {
168 if(Curl_raw_nequal(head->data, thisheader, thislen))
175 * Strip off leading and trailing whitespace from the value in the
176 * given HTTP header line and return a strdupped copy. Returns NULL in
177 * case of allocation failure. Returns an empty string if the header value
178 * consists entirely of whitespace.
180 static char *copy_header_value(const char *h)
189 /* Find the end of the header name */
190 while(*h && (*h != ':'))
194 /* Skip over colon */
197 /* Find the first non-space letter */
199 while(*start && ISSPACE(*start))
202 /* data is in the host encoding so
203 use '\r' and '\n' instead of 0x0d and 0x0a */
204 end = strchr(start, '\r');
206 end = strchr(start, '\n');
208 end = strchr(start, '\0');
212 /* skip all trailing space letters */
213 while((end > start) && ISSPACE(*end))
216 /* get length of the type */
219 value = malloc(len + 1);
223 memcpy(value, start, len);
224 value[len] = 0; /* zero terminate */
230 * http_output_basic() sets up an Authorization: header (or the proxy version)
231 * for HTTP Basic authentication.
235 static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
238 char *authorization = NULL;
239 struct SessionHandle *data = conn->data;
246 userp = &conn->allocptr.proxyuserpwd;
247 user = conn->proxyuser;
248 pwd = conn->proxypasswd;
251 userp = &conn->allocptr.userpwd;
256 snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd);
258 error = Curl_base64_encode(data,
259 data->state.buffer, strlen(data->state.buffer),
260 &authorization, &size);
265 return CURLE_REMOTE_ACCESS_DENIED;
267 Curl_safefree(*userp);
268 *userp = aprintf("%sAuthorization: Basic %s\r\n",
273 return CURLE_OUT_OF_MEMORY;
278 /* pickoneauth() selects the most favourable authentication method from the
279 * ones available and the ones we want.
281 * return TRUE if one was picked
283 static bool pickoneauth(struct auth *pick)
286 /* only deal with authentication we want */
287 unsigned long avail = pick->avail & pick->want;
290 /* The order of these checks is highly relevant, as this will be the order
291 of preference in case of the existence of multiple accepted types. */
292 if(avail & CURLAUTH_GSSNEGOTIATE)
293 pick->picked = CURLAUTH_GSSNEGOTIATE;
294 else if(avail & CURLAUTH_DIGEST)
295 pick->picked = CURLAUTH_DIGEST;
296 else if(avail & CURLAUTH_NTLM)
297 pick->picked = CURLAUTH_NTLM;
298 else if(avail & CURLAUTH_NTLM_WB)
299 pick->picked = CURLAUTH_NTLM_WB;
300 else if(avail & CURLAUTH_BASIC)
301 pick->picked = CURLAUTH_BASIC;
303 pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */
306 pick->avail = CURLAUTH_NONE; /* clear it here */
312 * Curl_http_perhapsrewind()
314 * If we are doing POST or PUT {
315 * If we have more data to send {
316 * If we are doing NTLM {
317 * Keep sending since we must not disconnect
320 * If there is more than just a little data left to send, close
321 * the current connection by force.
324 * If we have sent any data {
325 * If we don't have track of all the data {
326 * call app to tell it to rewind
329 * rewind internally so that the operation can restart fine
334 static CURLcode http_perhapsrewind(struct connectdata *conn)
336 struct SessionHandle *data = conn->data;
337 struct HTTP *http = data->state.proto.http;
338 curl_off_t bytessent;
339 curl_off_t expectsend = -1; /* default is unknown */
342 /* If this is still NULL, we have not reach very far and we can safely
343 skip this rewinding stuff */
346 switch(data->set.httpreq) {
354 bytessent = http->writebytecount;
356 if(conn->bits.authneg)
357 /* This is a state where we are known to be negotiating and we don't send
361 /* figure out how much data we are expected to send */
362 switch(data->set.httpreq) {
364 if(data->set.postfieldsize != -1)
365 expectsend = data->set.postfieldsize;
366 else if(data->set.postfields)
367 expectsend = (curl_off_t)strlen(data->set.postfields);
370 if(data->set.infilesize != -1)
371 expectsend = data->set.infilesize;
373 case HTTPREQ_POST_FORM:
374 expectsend = http->postsize;
381 conn->bits.rewindaftersend = FALSE; /* default */
383 if((expectsend == -1) || (expectsend > bytessent)) {
384 /* There is still data left to send */
385 if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
386 (data->state.authhost.picked == CURLAUTH_NTLM) ||
387 (data->state.authproxy.picked == CURLAUTH_NTLM_WB) ||
388 (data->state.authhost.picked == CURLAUTH_NTLM_WB)) {
389 if(((expectsend - bytessent) < 2000) ||
390 (conn->ntlm.state != NTLMSTATE_NONE)) {
391 /* The NTLM-negotiation has started *OR* there is just a little (<2K)
392 data left to send, keep on sending. */
394 /* rewind data when completely done sending! */
395 if(!conn->bits.authneg) {
396 conn->bits.rewindaftersend = TRUE;
397 infof(data, "Rewind stream after send\n");
403 /* this is already marked to get closed */
406 infof(data, "NTLM send, close instead of sending %" FORMAT_OFF_T
407 " bytes\n", (curl_off_t)(expectsend - bytessent));
410 /* This is not NTLM or NTLM with many bytes left to send: close
412 conn->bits.close = TRUE;
413 data->req.size = 0; /* don't download any more than 0 bytes */
415 /* There still is data left to send, but this connection is marked for
416 closure so we can safely do the rewind right now */
420 /* we rewind now at once since if we already sent something */
421 return Curl_readrewind(conn);
427 * Curl_http_auth_act() gets called when all HTTP headers have been received
428 * and it checks what authentication methods that are available and decides
429 * which one (if any) to use. It will set 'newurl' if an auth method was
433 CURLcode Curl_http_auth_act(struct connectdata *conn)
435 struct SessionHandle *data = conn->data;
436 bool pickhost = FALSE;
437 bool pickproxy = FALSE;
438 CURLcode code = CURLE_OK;
440 if(100 <= data->req.httpcode && 199 >= data->req.httpcode)
441 /* this is a transient response code, ignore */
444 if(data->state.authproblem)
445 return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
447 if(conn->bits.user_passwd &&
448 ((data->req.httpcode == 401) ||
449 (conn->bits.authneg && data->req.httpcode < 300))) {
450 pickhost = pickoneauth(&data->state.authhost);
452 data->state.authproblem = TRUE;
454 if(conn->bits.proxy_user_passwd &&
455 ((data->req.httpcode == 407) ||
456 (conn->bits.authneg && data->req.httpcode < 300))) {
457 pickproxy = pickoneauth(&data->state.authproxy);
459 data->state.authproblem = TRUE;
462 if(pickhost || pickproxy) {
463 /* In case this is GSS auth, the newurl field is already allocated so
464 we must make sure to free it before allocating a new one. As figured
465 out in bug #2284386 */
466 Curl_safefree(data->req.newurl);
467 data->req.newurl = strdup(data->change.url); /* clone URL */
468 if(!data->req.newurl)
469 return CURLE_OUT_OF_MEMORY;
471 if((data->set.httpreq != HTTPREQ_GET) &&
472 (data->set.httpreq != HTTPREQ_HEAD) &&
473 !conn->bits.rewindaftersend) {
474 code = http_perhapsrewind(conn);
480 else if((data->req.httpcode < 300) &&
481 (!data->state.authhost.done) &&
482 conn->bits.authneg) {
483 /* no (known) authentication available,
484 authentication is not "done" yet and
485 no authentication seems to be required and
486 we didn't try HEAD or GET */
487 if((data->set.httpreq != HTTPREQ_GET) &&
488 (data->set.httpreq != HTTPREQ_HEAD)) {
489 data->req.newurl = strdup(data->change.url); /* clone URL */
490 if(!data->req.newurl)
491 return CURLE_OUT_OF_MEMORY;
492 data->state.authhost.done = TRUE;
495 if(http_should_fail(conn)) {
496 failf (data, "The requested URL returned error: %d",
498 code = CURLE_HTTP_RETURNED_ERROR;
506 * Output the correct authentication header depending on the auth type
507 * and whether or not it is to a proxy.
510 output_auth_headers(struct connectdata *conn,
511 struct auth *authstatus,
516 struct SessionHandle *data = conn->data;
517 const char *auth=NULL;
518 CURLcode result = CURLE_OK;
519 #ifdef USE_HTTP_NEGOTIATE
520 struct negotiatedata *negdata = proxy?
521 &data->state.proxyneg:&data->state.negotiate;
524 #ifdef CURL_DISABLE_CRYPTO_AUTH
529 #ifdef USE_HTTP_NEGOTIATE
530 negdata->state = GSS_AUTHNONE;
531 if((authstatus->picked == CURLAUTH_GSSNEGOTIATE) &&
532 negdata->context && !GSS_ERROR(negdata->status)) {
533 auth="GSS-Negotiate";
534 result = Curl_output_negotiate(conn, proxy);
537 authstatus->done = TRUE;
538 negdata->state = GSS_AUTHSENT;
543 if(authstatus->picked == CURLAUTH_NTLM) {
545 result = Curl_output_ntlm(conn, proxy);
551 #if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
552 if(authstatus->picked == CURLAUTH_NTLM_WB) {
554 result = Curl_output_ntlm_wb(conn, proxy);
560 #ifndef CURL_DISABLE_CRYPTO_AUTH
561 if(authstatus->picked == CURLAUTH_DIGEST) {
563 result = Curl_output_digest(conn,
565 (const unsigned char *)request,
566 (const unsigned char *)path);
572 if(authstatus->picked == CURLAUTH_BASIC) {
574 if((proxy && conn->bits.proxy_user_passwd &&
575 !Curl_checkheaders(data, "Proxy-authorization:")) ||
576 (!proxy && conn->bits.user_passwd &&
577 !Curl_checkheaders(data, "Authorization:"))) {
579 result = http_output_basic(conn, proxy);
583 /* NOTE: this function should set 'done' TRUE, as the other auth
584 functions work that way */
585 authstatus->done = TRUE;
589 infof(data, "%s auth using %s with user '%s'\n",
590 proxy?"Proxy":"Server", auth,
591 proxy?(conn->proxyuser?conn->proxyuser:""):
592 (conn->user?conn->user:""));
593 authstatus->multi = (!authstatus->done) ? TRUE : FALSE;
596 authstatus->multi = FALSE;
602 * Curl_http_output_auth() setups the authentication headers for the
603 * host/proxy and the correct authentication
604 * method. conn->data->state.authdone is set to TRUE when authentication is
607 * @param conn all information about the current connection
608 * @param request pointer to the request keyword
609 * @param path pointer to the requested path
610 * @param proxytunnel boolean if this is the request setting up a "proxy
616 Curl_http_output_auth(struct connectdata *conn,
619 bool proxytunnel) /* TRUE if this is the request setting
620 up the proxy tunnel */
622 CURLcode result = CURLE_OK;
623 struct SessionHandle *data = conn->data;
624 struct auth *authhost;
625 struct auth *authproxy;
629 authhost = &data->state.authhost;
630 authproxy = &data->state.authproxy;
632 if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
633 conn->bits.user_passwd)
634 /* continue please */ ;
636 authhost->done = TRUE;
637 authproxy->done = TRUE;
638 return CURLE_OK; /* no authentication with no user or password */
641 if(authhost->want && !authhost->picked)
642 /* The app has selected one or more methods, but none has been picked
643 so far by a server round-trip. Then we set the picked one to the
644 want one, and if this is one single bit it'll be used instantly. */
645 authhost->picked = authhost->want;
647 if(authproxy->want && !authproxy->picked)
648 /* The app has selected one or more methods, but none has been picked so
649 far by a proxy round-trip. Then we set the picked one to the want one,
650 and if this is one single bit it'll be used instantly. */
651 authproxy->picked = authproxy->want;
653 #ifndef CURL_DISABLE_PROXY
654 /* Send proxy authentication header if needed */
655 if(conn->bits.httpproxy &&
656 (conn->bits.tunnel_proxy == proxytunnel)) {
657 result = output_auth_headers(conn, authproxy, request, path, TRUE);
664 #endif /* CURL_DISABLE_PROXY */
665 /* we have no proxy so let's pretend we're done authenticating
667 authproxy->done = TRUE;
669 /* To prevent the user+password to get sent to other than the original
670 host due to a location-follow, we do some weirdo checks here */
671 if(!data->state.this_is_a_follow ||
673 !data->state.first_host ||
674 data->set.http_disable_hostname_check_before_authentication ||
675 Curl_raw_equal(data->state.first_host, conn->host.name)) {
676 result = output_auth_headers(conn, authhost, request, path, FALSE);
679 authhost->done = TRUE;
686 * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
687 * headers. They are dealt with both in the transfer.c main loop and in the
688 * proxy CONNECT loop.
691 CURLcode Curl_http_input_auth(struct connectdata *conn,
693 const char *header) /* the first non-space */
696 * This resource requires authentication
698 struct SessionHandle *data = conn->data;
700 unsigned long *availp;
704 if(httpcode == 407) {
705 start = header+strlen("Proxy-authenticate:");
706 availp = &data->info.proxyauthavail;
707 authp = &data->state.authproxy;
710 start = header+strlen("WWW-Authenticate:");
711 availp = &data->info.httpauthavail;
712 authp = &data->state.authhost;
715 /* pass all white spaces */
716 while(*start && ISSPACE(*start))
720 * Here we check if we want the specific single authentication (using ==) and
721 * if we do, we initiate usage of it.
723 * If the provided authentication is wanted as one out of several accepted
724 * types (using &), we OR this authentication type to the authavail
729 * ->picked is first set to the 'want' value (one or more bits) before the
730 * request is sent, and then it is again set _after_ all response 401/407
731 * headers have been received but then only to a single preferred method
737 #ifdef USE_HTTP_NEGOTIATE
738 if(checkprefix("GSS-Negotiate", start) ||
739 checkprefix("Negotiate", start)) {
741 *availp |= CURLAUTH_GSSNEGOTIATE;
742 authp->avail |= CURLAUTH_GSSNEGOTIATE;
744 if(authp->picked == CURLAUTH_GSSNEGOTIATE) {
745 if(data->state.negotiate.state == GSS_AUTHSENT) {
746 /* if we sent GSS authentication in the outgoing request and we get
747 this back, we're in trouble */
748 infof(data, "Authentication problem. Ignoring this.\n");
749 data->state.authproblem = TRUE;
752 neg = Curl_input_negotiate(conn, (bool)(httpcode == 407), start);
754 DEBUGASSERT(!data->req.newurl);
755 data->req.newurl = strdup(data->change.url);
756 if(!data->req.newurl)
757 return CURLE_OUT_OF_MEMORY;
758 data->state.authproblem = FALSE;
759 /* we received GSS auth info and we dealt with it fine */
760 data->state.negotiate.state = GSS_AUTHRECV;
763 data->state.authproblem = TRUE;
770 /* NTLM support requires the SSL crypto libs */
771 if(checkprefix("NTLM", start)) {
772 *availp |= CURLAUTH_NTLM;
773 authp->avail |= CURLAUTH_NTLM;
774 if(authp->picked == CURLAUTH_NTLM ||
775 authp->picked == CURLAUTH_NTLM_WB) {
776 /* NTLM authentication is picked and activated */
778 Curl_input_ntlm(conn, (httpcode == 407)?TRUE:FALSE, start);
779 if(CURLE_OK == ntlm) {
780 data->state.authproblem = FALSE;
781 #ifdef NTLM_WB_ENABLED
782 if(authp->picked == CURLAUTH_NTLM_WB) {
783 *availp &= ~CURLAUTH_NTLM;
784 authp->avail &= ~CURLAUTH_NTLM;
785 *availp |= CURLAUTH_NTLM_WB;
786 authp->avail |= CURLAUTH_NTLM_WB;
788 /* Get the challenge-message which will be passed to
789 * ntlm_auth for generating the type 3 message later */
790 while(*start && ISSPACE(*start))
792 if(checkprefix("NTLM", start)) {
793 start += strlen("NTLM");
794 while(*start && ISSPACE(*start))
797 if((conn->challenge_header = strdup(start)) == NULL)
798 return CURLE_OUT_OF_MEMORY;
804 infof(data, "Authentication problem. Ignoring this.\n");
805 data->state.authproblem = TRUE;
811 #ifndef CURL_DISABLE_CRYPTO_AUTH
812 if(checkprefix("Digest", start)) {
813 if((authp->avail & CURLAUTH_DIGEST) != 0) {
814 infof(data, "Ignoring duplicate digest auth header.\n");
818 *availp |= CURLAUTH_DIGEST;
819 authp->avail |= CURLAUTH_DIGEST;
821 /* We call this function on input Digest headers even if Digest
822 * authentication isn't activated yet, as we need to store the
823 * incoming data from this header in case we are gonna use
825 dig = Curl_input_digest(conn, (httpcode == 407)?TRUE:FALSE, start);
827 if(CURLDIGEST_FINE != dig) {
828 infof(data, "Authentication problem. Ignoring this.\n");
829 data->state.authproblem = TRUE;
835 if(checkprefix("Basic", start)) {
836 *availp |= CURLAUTH_BASIC;
837 authp->avail |= CURLAUTH_BASIC;
838 if(authp->picked == CURLAUTH_BASIC) {
839 /* We asked for Basic authentication but got a 40X back
840 anyway, which basically means our name+password isn't
842 authp->avail = CURLAUTH_NONE;
843 infof(data, "Authentication problem. Ignoring this.\n");
844 data->state.authproblem = TRUE;
848 /* there may be multiple methods on one line, so keep reading */
849 while(*start && *start != ',') /* read up to the next comma */
851 if(*start == ',') /* if we're on a comma, skip it */
853 while(*start && ISSPACE(*start))
860 * http_should_fail() determines whether an HTTP response has gotten us
861 * into an error state or not.
863 * @param conn all information about the current connection
865 * @retval 0 communications should continue
867 * @retval 1 communications should not continue
869 static int http_should_fail(struct connectdata *conn)
871 struct SessionHandle *data;
878 httpcode = data->req.httpcode;
881 ** If we haven't been asked to fail on error,
884 if(!data->set.http_fail_on_error)
888 ** Any code < 400 is never terminal.
893 if(data->state.resume_from &&
894 (data->set.httpreq==HTTPREQ_GET) &&
896 /* "Requested Range Not Satisfiable", just proceed and
897 pretend this is no error */
902 ** Any code >= 400 that's not 401 or 407 is always
905 if((httpcode != 401) &&
910 ** All we have left to deal with is 401 and 407
912 DEBUGASSERT((httpcode == 401) || (httpcode == 407));
915 ** Examine the current authentication state to see if this
916 ** is an error. The idea is for this function to get
917 ** called after processing all the headers in a response
918 ** message. So, if we've been to asked to authenticate a
919 ** particular stage, and we've done it, we're OK. But, if
920 ** we're already completely authenticated, it's not OK to
921 ** get another 401 or 407.
923 ** It is possible for authentication to go stale such that
924 ** the client needs to reauthenticate. Once that info is
925 ** available, use it here.
929 ** Either we're not authenticating, or we're supposed to
930 ** be authenticating something else. This is an error.
932 if((httpcode == 401) && !conn->bits.user_passwd)
934 if((httpcode == 407) && !conn->bits.proxy_user_passwd)
937 return data->state.authproblem;
941 * readmoredata() is a "fread() emulation" to provide POST and/or request
942 * data. It is used when a huge POST is to be made and the entire chunk wasn't
943 * sent in the first send(). This function will then be called from the
944 * transfer.c loop when more data is to be sent to the peer.
946 * Returns the amount of bytes it filled the buffer with.
948 static size_t readmoredata(char *buffer,
953 struct connectdata *conn = (struct connectdata *)userp;
954 struct HTTP *http = conn->data->state.proto.http;
955 size_t fullsize = size * nitems;
957 if(0 == http->postsize)
958 /* nothing to return */
961 /* make sure that a HTTP request is never sent away chunked! */
962 conn->data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
964 if(http->postsize <= (curl_off_t)fullsize) {
965 memcpy(buffer, http->postdata, (size_t)http->postsize);
966 fullsize = (size_t)http->postsize;
968 if(http->backup.postsize) {
969 /* move backup data into focus and continue on that */
970 http->postdata = http->backup.postdata;
971 http->postsize = http->backup.postsize;
972 conn->fread_func = http->backup.fread_func;
973 conn->fread_in = http->backup.fread_in;
975 http->sending++; /* move one step up */
977 http->backup.postsize=0;
985 memcpy(buffer, http->postdata, fullsize);
986 http->postdata += fullsize;
987 http->postsize -= fullsize;
992 /* ------------------------------------------------------------------------- */
993 /* add_buffer functions */
996 * Curl_add_buffer_init() sets up and returns a fine buffer struct
998 Curl_send_buffer *Curl_add_buffer_init(void)
1000 return calloc(1, sizeof(Curl_send_buffer));
1004 * Curl_add_buffer_send() sends a header buffer and frees all associated
1005 * memory. Body data may be appended to the header data if desired.
1009 CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
1010 struct connectdata *conn,
1012 /* add the number of sent bytes to this
1014 long *bytes_written,
1016 /* how much of the buffer contains body data */
1017 size_t included_body_bytes,
1025 struct HTTP *http = conn->data->state.proto.http;
1027 curl_socket_t sockfd;
1030 DEBUGASSERT(socketindex <= SECONDARYSOCKET);
1032 sockfd = conn->sock[socketindex];
1034 /* The looping below is required since we use non-blocking sockets, but due
1035 to the circumstances we will just loop and try again and again etc */
1038 size = in->size_used;
1040 headersize = size - included_body_bytes; /* the initial part that isn't body
1043 DEBUGASSERT(size > included_body_bytes);
1045 res = Curl_convert_to_network(conn->data, ptr, headersize);
1046 /* Curl_convert_to_network calls failf if unsuccessful */
1048 /* conversion failed, free memory and return to the caller */
1055 if(conn->handler->flags & PROTOPT_SSL) {
1056 /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
1057 when we speak HTTPS, as if only a fraction of it is sent now, this data
1058 needs to fit into the normal read-callback buffer later on and that
1059 buffer is using this size.
1062 sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:size;
1064 /* OpenSSL is very picky and we must send the SAME buffer pointer to the
1065 library when we attempt to re-send this buffer. Sending the same data
1066 is not enough, we must use the exact same address. For this reason, we
1067 must copy the data to the uploadbuffer first, since that is the buffer
1068 we will be using if this send is retried later.
1070 memcpy(conn->data->state.uploadbuffer, ptr, sendsize);
1071 ptr = conn->data->state.uploadbuffer;
1076 res = Curl_write(conn, sockfd, ptr, sendsize, &amount);
1078 if(CURLE_OK == res) {
1080 * Note that we may not send the entire chunk at once, and we have a set
1081 * number of data bytes at the end of the big buffer (out of which we may
1082 * only send away a part).
1084 /* how much of the header that was sent */
1085 size_t headlen = (size_t)amount>headersize?headersize:(size_t)amount;
1086 size_t bodylen = amount - headlen;
1088 if(conn->data->set.verbose) {
1089 /* this data _may_ contain binary stuff */
1090 Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, headlen, conn);
1091 if((size_t)amount > headlen) {
1092 /* there was body data sent beyond the initial header part, pass that
1093 on to the debug callback too */
1094 Curl_debug(conn->data, CURLINFO_DATA_OUT,
1095 ptr+headlen, bodylen, conn);
1099 /* since we sent a piece of the body here, up the byte counter for it
1101 http->writebytecount += bodylen;
1103 /* 'amount' can never be a very large value here so typecasting it so a
1104 signed 31 bit value should not cause problems even if ssize_t is
1106 *bytes_written += (long)amount;
1109 if((size_t)amount != size) {
1110 /* The whole request could not be sent in one system call. We must
1111 queue it up and send it later when we get the chance. We must not
1112 loop here and wait until it might work again. */
1116 ptr = in->buffer + amount;
1118 /* backup the currently set pointers */
1119 http->backup.fread_func = conn->fread_func;
1120 http->backup.fread_in = conn->fread_in;
1121 http->backup.postdata = http->postdata;
1122 http->backup.postsize = http->postsize;
1124 /* set the new pointers for the request-sending */
1125 conn->fread_func = (curl_read_callback)readmoredata;
1126 conn->fread_in = (void *)conn;
1127 http->postdata = ptr;
1128 http->postsize = (curl_off_t)size;
1130 http->send_buffer = in;
1131 http->sending = HTTPSEND_REQUEST;
1135 http->sending = HTTPSEND_BODY;
1136 /* the full buffer was sent, clean up and return */
1139 if((size_t)amount != size)
1140 /* We have no continue-send mechanism now, fail. This can only happen
1141 when this function is used from the CONNECT sending function. We
1142 currently (stupidly) assume that the whole request is always sent
1143 away in the first single chunk.
1147 return CURLE_SEND_ERROR;
1149 conn->writechannel_inuse = FALSE;
1161 * add_bufferf() add the formatted input to the buffer.
1163 CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...)
1168 s = vaprintf(fmt, ap); /* this allocs a new string to append */
1172 CURLcode result = Curl_add_buffer(in, s, strlen(s));
1176 /* If we failed, we cleanup the whole buffer and return error */
1180 return CURLE_OUT_OF_MEMORY;
1184 * add_buffer() appends a memory chunk to the existing buffer
1186 CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
1191 if(~size < in->size_used) {
1192 /* If resulting used size of send buffer would wrap size_t, cleanup
1193 the whole buffer and return error. Otherwise the required buffer
1194 size will fit into a single allocatable memory chunk */
1195 Curl_safefree(in->buffer);
1197 return CURLE_OUT_OF_MEMORY;
1201 ((in->size_used + size) > (in->size_max - 1))) {
1203 /* If current buffer size isn't enough to hold the result, use a
1204 buffer size that doubles the required size. If this new size
1205 would wrap size_t, then just use the largest possible one */
1207 if((size > (size_t)-1/2) || (in->size_used > (size_t)-1/2) ||
1208 (~(size*2) < (in->size_used*2)))
1209 new_size = (size_t)-1;
1211 new_size = (in->size_used+size)*2;
1214 /* we have a buffer, enlarge the existing one */
1215 new_rb = realloc(in->buffer, new_size);
1217 /* create a new buffer */
1218 new_rb = malloc(new_size);
1221 /* If we failed, we cleanup the whole buffer and return error */
1222 Curl_safefree(in->buffer);
1224 return CURLE_OUT_OF_MEMORY;
1227 in->buffer = new_rb;
1228 in->size_max = new_size;
1230 memcpy(&in->buffer[in->size_used], inptr, size);
1232 in->size_used += size;
1237 /* end of the add_buffer functions */
1238 /* ------------------------------------------------------------------------- */
1243 * Curl_compareheader()
1245 * Returns TRUE if 'headerline' contains the 'header' with given 'content'.
1246 * Pass headers WITH the colon.
1249 Curl_compareheader(const char *headerline, /* line to check */
1250 const char *header, /* header keyword _with_ colon */
1251 const char *content) /* content string to find */
1253 /* RFC2616, section 4.2 says: "Each header field consists of a name followed
1254 * by a colon (":") and the field value. Field names are case-insensitive.
1255 * The field value MAY be preceded by any amount of LWS, though a single SP
1258 size_t hlen = strlen(header);
1264 if(!Curl_raw_nequal(headerline, header, hlen))
1265 return FALSE; /* doesn't start with header */
1267 /* pass the header */
1268 start = &headerline[hlen];
1270 /* pass all white spaces */
1271 while(*start && ISSPACE(*start))
1274 /* find the end of the header line */
1275 end = strchr(start, '\r'); /* lines end with CRLF */
1277 /* in case there's a non-standard compliant line here */
1278 end = strchr(start, '\n');
1281 /* hm, there's no line ending here, use the zero byte! */
1282 end = strchr(start, '\0');
1285 len = end-start; /* length of the content part of the input line */
1286 clen = strlen(content); /* length of the word to find */
1288 /* find the content string in the rest of the line */
1289 for(;len>=clen;len--, start++) {
1290 if(Curl_raw_nequal(start, content, clen))
1291 return TRUE; /* match! */
1294 return FALSE; /* no match */
1298 * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
1299 * the generic Curl_connect().
1301 CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
1303 struct SessionHandle *data;
1308 /* We default to persistent connections. We set this already in this connect
1309 function to make the re-use checks properly be able to check this bit. */
1310 conn->bits.close = FALSE;
1312 if(data->state.used_interface == Curl_if_multi) {
1313 /* when the multi interface is used, the CONNECT procedure might not have
1315 result = Curl_proxy_connect(conn);
1320 if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
1321 /* nothing else to do except wait right now - we're not done here. */
1324 if(conn->given->flags & PROTOPT_SSL) {
1325 /* perform SSL initialization */
1326 if(data->state.used_interface == Curl_if_multi) {
1327 result = https_connecting(conn, done);
1333 result = Curl_ssl_connect(conn, FIRSTSOCKET);
1346 /* this returns the socket to wait for in the DO and DOING state for the multi
1347 interface and then we're always _sending_ a request and thus we wait for
1348 the single socket to become writable only */
1349 static int http_getsock_do(struct connectdata *conn,
1350 curl_socket_t *socks,
1354 (void)numsocks; /* unused, we trust it to be at least 1 */
1355 socks[0] = conn->sock[FIRSTSOCKET];
1356 return GETSOCK_WRITESOCK(0);
1360 static CURLcode https_connecting(struct connectdata *conn, bool *done)
1363 DEBUGASSERT((conn) && (conn->handler->flags & PROTOPT_SSL));
1365 /* perform SSL initialization for this socket */
1366 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done);
1368 conn->bits.close = TRUE; /* a failed connection is marked for closure
1369 to prevent (bad) re-use or similar */
1374 #if defined(USE_SSLEAY) || defined(USE_GNUTLS)
1375 /* This function is for OpenSSL and GnuTLS only. It should be made to query
1376 the generic SSL layer instead. */
1377 static int https_getsock(struct connectdata *conn,
1378 curl_socket_t *socks,
1381 if(conn->handler->flags & PROTOPT_SSL) {
1382 struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
1385 return GETSOCK_BLANK;
1387 if(connssl->connecting_state == ssl_connect_2_writing) {
1389 socks[0] = conn->sock[FIRSTSOCKET];
1390 return GETSOCK_WRITESOCK(0);
1392 else if(connssl->connecting_state == ssl_connect_2_reading) {
1394 socks[0] = conn->sock[FIRSTSOCKET];
1395 return GETSOCK_READSOCK(0);
1401 #if defined(USE_NSS) || defined(USE_QSOSSL) || \
1402 defined(USE_POLARSSL) || defined(USE_AXTLS) || defined(USE_CYASSL)
1403 static int https_getsock(struct connectdata *conn,
1404 curl_socket_t *socks,
1410 return GETSOCK_BLANK;
1412 #endif /* USE_AXTLS || USE_POLARSSL || USE_QSOSSL || USE_NSS */
1413 #endif /* USE_SSLEAY || USE_GNUTLS */
1416 * Curl_http_done() gets called from Curl_done() after a single HTTP request
1417 * has been performed.
1420 CURLcode Curl_http_done(struct connectdata *conn,
1421 CURLcode status, bool premature)
1423 struct SessionHandle *data = conn->data;
1424 struct HTTP *http =data->state.proto.http;
1426 Curl_unencode_cleanup(conn);
1428 /* set the proper values (possibly modified on POST) */
1429 conn->fread_func = data->set.fread_func; /* restore */
1430 conn->fread_in = data->set.in; /* restore */
1431 conn->seek_func = data->set.seek_func; /* restore */
1432 conn->seek_client = data->set.seek_client; /* restore */
1437 if(http->send_buffer) {
1438 Curl_send_buffer *buff = http->send_buffer;
1442 http->send_buffer = NULL; /* clear the pointer */
1445 if(HTTPREQ_POST_FORM == data->set.httpreq) {
1446 data->req.bytecount = http->readbytecount + http->writebytecount;
1448 Curl_formclean(&http->sendit); /* Now free that whole lot */
1450 /* a file being uploaded was left opened, close it! */
1451 fclose(http->form.fp);
1452 http->form.fp = NULL;
1455 else if(HTTPREQ_PUT == data->set.httpreq)
1456 data->req.bytecount = http->readbytecount + http->writebytecount;
1458 if(status != CURLE_OK)
1461 if(!premature && /* this check is pointless when DONE is called before the
1462 entire operation is complete */
1463 !conn->bits.retry &&
1464 ((http->readbytecount +
1465 data->req.headerbytecount -
1466 data->req.deductheadercount)) <= 0) {
1467 /* If this connection isn't simply closed to be retried, AND nothing was
1468 read from the HTTP server (that counts), this can't be right so we
1469 return an error here */
1470 failf(data, "Empty reply from server");
1471 return CURLE_GOT_NOTHING;
1478 /* Determine if we should use HTTP 1.1 for this request. Reasons to avoid it
1479 are if the user specifically requested HTTP 1.0, if the server we are
1480 connected to only supports 1.0, or if any server previously contacted to
1481 handle this request only supports 1.0. */
1482 static bool use_http_1_1(const struct SessionHandle *data,
1483 const struct connectdata *conn)
1485 return ((data->set.httpversion == CURL_HTTP_VERSION_1_1) ||
1486 ((data->set.httpversion != CURL_HTTP_VERSION_1_0) &&
1487 ((conn->httpversion == 11) ||
1488 ((conn->httpversion != 10) &&
1489 (data->state.httpversion != 10))))) ? TRUE : FALSE;
1492 /* check and possibly add an Expect: header */
1493 static CURLcode expect100(struct SessionHandle *data,
1494 struct connectdata *conn,
1495 Curl_send_buffer *req_buffer)
1497 CURLcode result = CURLE_OK;
1499 data->state.expect100header = FALSE; /* default to false unless it is set
1501 if(use_http_1_1(data, conn)) {
1502 /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect:
1503 100-continue to the headers which actually speeds up post operations
1504 (as there is one packet coming back from the web server) */
1505 ptr = Curl_checkheaders(data, "Expect:");
1507 data->state.expect100header =
1508 Curl_compareheader(ptr, "Expect:", "100-continue");
1511 result = Curl_add_bufferf(req_buffer,
1512 "Expect: 100-continue\r\n");
1513 if(result == CURLE_OK)
1514 data->state.expect100header = TRUE;
1520 CURLcode Curl_add_custom_headers(struct connectdata *conn,
1521 Curl_send_buffer *req_buffer)
1524 struct curl_slist *headers=conn->data->set.headers;
1527 ptr = strchr(headers->data, ':');
1529 /* we require a colon for this to be a true header */
1531 ptr++; /* pass the colon */
1532 while(*ptr && ISSPACE(*ptr))
1536 /* only send this if the contents was non-blank */
1538 if(conn->allocptr.host &&
1539 /* a Host: header was sent already, don't pass on any custom Host:
1540 header as that will produce *two* in the same request! */
1541 checkprefix("Host:", headers->data))
1543 else if(conn->data->set.httpreq == HTTPREQ_POST_FORM &&
1544 /* this header (extended by formdata.c) is sent later */
1545 checkprefix("Content-Type:", headers->data))
1547 else if(conn->bits.authneg &&
1548 /* while doing auth neg, don't allow the custom length since
1549 we will force length zero then */
1550 checkprefix("Content-Length", headers->data))
1552 else if(conn->allocptr.te &&
1553 /* when asking for Transfer-Encoding, don't pass on a custom
1555 checkprefix("Connection", headers->data))
1558 CURLcode result = Curl_add_bufferf(req_buffer, "%s\r\n",
1566 ptr = strchr(headers->data, ';');
1569 ptr++; /* pass the semicolon */
1570 while(*ptr && ISSPACE(*ptr))
1574 /* this may be used for something else in the future */
1577 if(*(--ptr) == ';') {
1580 /* send no-value custom header if terminated by semicolon */
1582 result = Curl_add_bufferf(req_buffer, "%s\r\n",
1590 headers = headers->next;
1595 CURLcode Curl_add_timecondition(struct SessionHandle *data,
1596 Curl_send_buffer *req_buffer)
1598 const struct tm *tm;
1599 char *buf = data->state.buffer;
1600 CURLcode result = CURLE_OK;
1603 result = Curl_gmtime(data->set.timevalue, &keeptime);
1605 failf(data, "Invalid TIMEVALUE\n");
1610 /* The If-Modified-Since header family should have their times set in
1611 * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be
1612 * represented in Greenwich Mean Time (GMT), without exception. For the
1613 * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal
1614 * Time)." (see page 20 of RFC2616).
1617 /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
1618 snprintf(buf, BUFSIZE-1,
1619 "%s, %02d %s %4d %02d:%02d:%02d GMT",
1620 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
1622 Curl_month[tm->tm_mon],
1628 switch(data->set.timecondition) {
1629 case CURL_TIMECOND_IFMODSINCE:
1631 result = Curl_add_bufferf(req_buffer,
1632 "If-Modified-Since: %s\r\n", buf);
1634 case CURL_TIMECOND_IFUNMODSINCE:
1635 result = Curl_add_bufferf(req_buffer,
1636 "If-Unmodified-Since: %s\r\n", buf);
1638 case CURL_TIMECOND_LASTMOD:
1639 result = Curl_add_bufferf(req_buffer,
1640 "Last-Modified: %s\r\n", buf);
1648 * Curl_http() gets called from the generic Curl_do() function when a HTTP
1649 * request is to be performed. This creates and sends a properly constructed
1652 CURLcode Curl_http(struct connectdata *conn, bool *done)
1654 struct SessionHandle *data=conn->data;
1655 CURLcode result=CURLE_OK;
1657 const char *ppath = data->state.path;
1658 bool paste_ftp_userpwd = FALSE;
1659 char ftp_typecode[sizeof("/;type=?")] = "";
1660 const char *host = conn->host.name;
1661 const char *te = ""; /* transfer-encoding */
1663 const char *request;
1664 Curl_HttpReq httpreq = data->set.httpreq;
1665 char *addcookies = NULL;
1666 curl_off_t included_body = 0;
1667 const char *httpstring;
1668 Curl_send_buffer *req_buffer;
1669 curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */
1670 int seekerr = CURL_SEEKFUNC_OK;
1672 /* Always consider the DO phase done after this function call, even if there
1673 may be parts of the request that is not yet sent, since we can deal with
1674 the rest of the request in the PERFORM phase. */
1677 /* If there already is a protocol-specific struct allocated for this
1678 sessionhandle, deal with it */
1679 Curl_reset_reqproto(conn);
1681 if(!data->state.proto.http) {
1682 /* Only allocate this struct if we don't already have it! */
1684 http = calloc(1, sizeof(struct HTTP));
1686 return CURLE_OUT_OF_MEMORY;
1687 data->state.proto.http = http;
1690 http = data->state.proto.http;
1692 if(!data->state.this_is_a_follow) {
1693 /* this is not a followed location, get the original host name */
1694 if(data->state.first_host)
1695 /* Free to avoid leaking memory on multiple requests*/
1696 free(data->state.first_host);
1698 data->state.first_host = strdup(conn->host.name);
1699 if(!data->state.first_host)
1700 return CURLE_OUT_OF_MEMORY;
1702 http->writebytecount = http->readbytecount = 0;
1704 if((conn->handler->protocol&(CURLPROTO_HTTP|CURLPROTO_FTP)) &&
1706 httpreq = HTTPREQ_PUT;
1709 /* Now set the 'request' pointer to the proper request string */
1710 if(data->set.str[STRING_CUSTOMREQUEST])
1711 request = data->set.str[STRING_CUSTOMREQUEST];
1713 if(data->set.opt_no_body)
1716 DEBUGASSERT((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST));
1719 case HTTPREQ_POST_FORM:
1725 default: /* this should never happen */
1736 /* The User-Agent string might have been allocated in url.c already, because
1737 it might have been used in the proxy connect, but if we have got a header
1738 with the user-agent string specified, we erase the previously made string
1740 if(Curl_checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
1741 free(conn->allocptr.uagent);
1742 conn->allocptr.uagent=NULL;
1745 /* setup the authentication headers */
1746 result = Curl_http_output_auth(conn, request, ppath, FALSE);
1750 if((data->state.authhost.multi || data->state.authproxy.multi) &&
1751 (httpreq != HTTPREQ_GET) &&
1752 (httpreq != HTTPREQ_HEAD)) {
1753 /* Auth is required and we are not authenticated yet. Make a PUT or POST
1754 with content-length zero as a "probe". */
1755 conn->bits.authneg = TRUE;
1758 conn->bits.authneg = FALSE;
1760 Curl_safefree(conn->allocptr.ref);
1761 if(data->change.referer && !Curl_checkheaders(data, "Referer:"))
1762 conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
1764 conn->allocptr.ref = NULL;
1766 if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(data, "Cookie:"))
1767 addcookies = data->set.str[STRING_COOKIE];
1769 if(!Curl_checkheaders(data, "Accept-Encoding:") &&
1770 data->set.str[STRING_ENCODING]) {
1771 Curl_safefree(conn->allocptr.accept_encoding);
1772 conn->allocptr.accept_encoding =
1773 aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
1774 if(!conn->allocptr.accept_encoding)
1775 return CURLE_OUT_OF_MEMORY;
1779 /* we only consider transfer-encoding magic if libz support is built-in */
1781 if(!Curl_checkheaders(data, "TE:") && data->set.http_transfer_encoding) {
1782 /* When we are to insert a TE: header in the request, we must also insert
1783 TE in a Connection: header, so we need to merge the custom provided
1784 Connection: header and prevent the original to get sent. Note that if
1785 the user has inserted his/hers own TE: header we don't do this magic
1786 but then assume that the user will handle it all! */
1787 char *cptr = Curl_checkheaders(data, "Connection:");
1788 #define TE_HEADER "TE: gzip\r\n"
1790 Curl_safefree(conn->allocptr.te);
1792 /* Create the (updated) Connection: header */
1793 conn->allocptr.te = cptr? aprintf("%s, TE\r\n" TE_HEADER, cptr):
1794 strdup("Connection: TE\r\n" TE_HEADER);
1796 if(!conn->allocptr.te)
1797 return CURLE_OUT_OF_MEMORY;
1801 ptr = Curl_checkheaders(data, "Transfer-Encoding:");
1803 /* Some kind of TE is requested, check if 'chunked' is chosen */
1804 data->req.upload_chunky =
1805 Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
1808 if((conn->handler->protocol&CURLPROTO_HTTP) &&
1810 (data->set.infilesize == -1)) {
1811 if(conn->bits.authneg)
1812 /* don't enable chunked during auth neg */
1814 else if(use_http_1_1(data, conn)) {
1815 /* HTTP, upload, unknown file size and not HTTP 1.0 */
1816 data->req.upload_chunky = TRUE;
1819 failf(data, "Chunky upload is not supported by HTTP 1.0");
1820 return CURLE_UPLOAD_FAILED;
1824 /* else, no chunky upload */
1825 data->req.upload_chunky = FALSE;
1828 if(data->req.upload_chunky)
1829 te = "Transfer-Encoding: chunked\r\n";
1832 Curl_safefree(conn->allocptr.host);
1834 ptr = Curl_checkheaders(data, "Host:");
1835 if(ptr && (!data->state.this_is_a_follow ||
1836 Curl_raw_equal(data->state.first_host, conn->host.name))) {
1837 #if !defined(CURL_DISABLE_COOKIES)
1838 /* If we have a given custom Host: header, we extract the host name in
1839 order to possibly use it for cookie reasons later on. We only allow the
1840 custom Host: header if this is NOT a redirect, as setting Host: in the
1841 redirected request is being out on thin ice. Except if the host name
1842 is the same as the first one! */
1843 char *cookiehost = copy_header_value(ptr);
1845 return CURLE_OUT_OF_MEMORY;
1847 /* ignore empty data */
1850 /* If the host begins with '[', we start searching for the port after
1851 the bracket has been closed */
1852 int startsearch = 0;
1853 if(*cookiehost == '[') {
1854 char *closingbracket;
1855 /* since the 'cookiehost' is an allocated memory area that will be
1856 freed later we cannot simply increment the pointer */
1857 memmove(cookiehost, cookiehost + 1, strlen(cookiehost) - 1);
1858 closingbracket = strchr(cookiehost, ']');
1860 *closingbracket = 0;
1863 char *colon = strchr(cookiehost + startsearch, ':');
1865 *colon = 0; /* The host must not include an embedded port number */
1867 Curl_safefree(conn->allocptr.cookiehost);
1868 conn->allocptr.cookiehost = cookiehost;
1872 conn->allocptr.host = NULL;
1875 /* When building Host: headers, we must put the host name within
1876 [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
1878 if(((conn->given->protocol&CURLPROTO_HTTPS) &&
1879 (conn->remote_port == PORT_HTTPS)) ||
1880 ((conn->given->protocol&CURLPROTO_HTTP) &&
1881 (conn->remote_port == PORT_HTTP)) )
1882 /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include
1883 the port number in the host string */
1884 conn->allocptr.host = aprintf("Host: %s%s%s\r\n",
1885 conn->bits.ipv6_ip?"[":"",
1887 conn->bits.ipv6_ip?"]":"");
1889 conn->allocptr.host = aprintf("Host: %s%s%s:%hu\r\n",
1890 conn->bits.ipv6_ip?"[":"",
1892 conn->bits.ipv6_ip?"]":"",
1895 if(!conn->allocptr.host)
1896 /* without Host: we can't make a nice request */
1897 return CURLE_OUT_OF_MEMORY;
1900 #ifndef CURL_DISABLE_PROXY
1901 if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
1902 /* Using a proxy but does not tunnel through it */
1904 /* The path sent to the proxy is in fact the entire URL. But if the remote
1905 host is a IDN-name, we must make sure that the request we produce only
1906 uses the encoded host name! */
1907 if(conn->host.dispname != conn->host.name) {
1908 char *url = data->change.url;
1909 ptr = strstr(url, conn->host.dispname);
1911 /* This is where the display name starts in the URL, now replace this
1912 part with the encoded name. TODO: This method of replacing the host
1913 name is rather crude as I believe there's a slight risk that the
1914 user has entered a user name or password that contain the host name
1916 size_t currlen = strlen(conn->host.dispname);
1917 size_t newlen = strlen(conn->host.name);
1918 size_t urllen = strlen(url);
1922 newurl = malloc(urllen + newlen - currlen + 1);
1924 /* copy the part before the host name */
1925 memcpy(newurl, url, ptr - url);
1926 /* append the new host name instead of the old */
1927 memcpy(newurl + (ptr - url), conn->host.name, newlen);
1928 /* append the piece after the host name */
1929 memcpy(newurl + newlen + (ptr - url),
1930 ptr + currlen, /* copy the trailing zero byte too */
1931 urllen - (ptr-url) - currlen + 1);
1932 if(data->change.url_alloc) {
1933 Curl_safefree(data->change.url);
1934 data->change.url_alloc = FALSE;
1936 data->change.url = newurl;
1937 data->change.url_alloc = TRUE;
1940 return CURLE_OUT_OF_MEMORY;
1943 ppath = data->change.url;
1944 if(checkprefix("ftp://", ppath)) {
1945 if(data->set.proxy_transfer_mode) {
1946 /* when doing ftp, append ;type=<a|i> if not present */
1947 char *type = strstr(ppath, ";type=");
1948 if(type && type[6] && type[7] == 0) {
1949 switch (Curl_raw_toupper(type[6])) {
1959 char *p = ftp_typecode;
1960 /* avoid sending invalid URLs like ftp://example.com;type=i if the
1961 * user specified ftp://example.com without the slash */
1962 if(!*data->state.path && ppath[strlen(ppath) - 1] != '/') {
1965 snprintf(p, sizeof(ftp_typecode) - 1, ";type=%c",
1966 data->set.prefer_ascii ? 'a' : 'i');
1969 if(conn->bits.user_passwd && !conn->bits.userpwd_in_url)
1970 paste_ftp_userpwd = TRUE;
1973 #endif /* CURL_DISABLE_PROXY */
1975 if(HTTPREQ_POST_FORM == httpreq) {
1976 /* we must build the whole post sequence first, so that we have a size of
1977 the whole transfer before we start to send it */
1978 result = Curl_getformdata(data, &http->sendit, data->set.httppost,
1979 Curl_checkheaders(data, "Content-Type:"),
1985 http->p_accept = Curl_checkheaders(data, "Accept:")?NULL:"Accept: */*\r\n";
1987 if(( (HTTPREQ_POST == httpreq) ||
1988 (HTTPREQ_POST_FORM == httpreq) ||
1989 (HTTPREQ_PUT == httpreq) ) &&
1990 data->state.resume_from) {
1991 /**********************************************************************
1992 * Resuming upload in HTTP means that we PUT or POST and that we have
1993 * got a resume_from value set. The resume value has already created
1994 * a Range: header that will be passed along. We need to "fast forward"
1995 * the file the given number of bytes and decrease the assume upload
1996 * file size before we continue this venture in the dark lands of HTTP.
1997 *********************************************************************/
1999 if(data->state.resume_from < 0 ) {
2001 * This is meant to get the size of the present remote-file by itself.
2002 * We don't support this now. Bail out!
2004 data->state.resume_from = 0;
2007 if(data->state.resume_from && !data->state.this_is_a_follow) {
2008 /* do we still game? */
2010 /* Now, let's read off the proper amount of bytes from the
2012 if(conn->seek_func) {
2013 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
2017 if(seekerr != CURL_SEEKFUNC_OK) {
2018 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
2019 failf(data, "Could not seek stream");
2020 return CURLE_READ_ERROR;
2022 /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
2024 curl_off_t passed=0;
2026 size_t readthisamountnow =
2027 (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
2028 BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
2030 size_t actuallyread =
2031 data->set.fread_func(data->state.buffer, 1, readthisamountnow,
2034 passed += actuallyread;
2035 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
2036 /* this checks for greater-than only to make sure that the
2037 CURL_READFUNC_ABORT return code still aborts */
2038 failf(data, "Could only read %" FORMAT_OFF_T
2039 " bytes from the input",
2041 return CURLE_READ_ERROR;
2043 } while(passed < data->state.resume_from);
2047 /* now, decrease the size of the read */
2048 if(data->set.infilesize>0) {
2049 data->set.infilesize -= data->state.resume_from;
2051 if(data->set.infilesize <= 0) {
2052 failf(data, "File already completely uploaded");
2053 return CURLE_PARTIAL_FILE;
2056 /* we've passed, proceed as normal */
2059 if(data->state.use_range) {
2061 * A range is selected. We use different headers whether we're downloading
2062 * or uploading and we always let customized headers override our internal
2063 * ones if any such are specified.
2065 if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
2066 !Curl_checkheaders(data, "Range:")) {
2067 /* if a line like this was already allocated, free the previous one */
2068 if(conn->allocptr.rangeline)
2069 free(conn->allocptr.rangeline);
2070 conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n",
2073 else if((httpreq != HTTPREQ_GET) &&
2074 !Curl_checkheaders(data, "Content-Range:")) {
2076 /* if a line like this was already allocated, free the previous one */
2077 if(conn->allocptr.rangeline)
2078 free(conn->allocptr.rangeline);
2080 if(data->set.set_resume_from < 0) {
2081 /* Upload resume was asked for, but we don't know the size of the
2082 remote part so we tell the server (and act accordingly) that we
2083 upload the whole file (again) */
2084 conn->allocptr.rangeline =
2085 aprintf("Content-Range: bytes 0-%" FORMAT_OFF_T
2086 "/%" FORMAT_OFF_T "\r\n",
2087 data->set.infilesize - 1, data->set.infilesize);
2090 else if(data->state.resume_from) {
2091 /* This is because "resume" was selected */
2092 curl_off_t total_expected_size=
2093 data->state.resume_from + data->set.infilesize;
2094 conn->allocptr.rangeline =
2095 aprintf("Content-Range: bytes %s%" FORMAT_OFF_T
2096 "/%" FORMAT_OFF_T "\r\n",
2097 data->state.range, total_expected_size-1,
2098 total_expected_size);
2101 /* Range was selected and then we just pass the incoming range and
2102 append total size */
2103 conn->allocptr.rangeline =
2104 aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n",
2105 data->state.range, data->set.infilesize);
2107 if(!conn->allocptr.rangeline)
2108 return CURLE_OUT_OF_MEMORY;
2112 /* Use 1.1 unless the user specifically asked for 1.0 or the server only
2114 httpstring= use_http_1_1(data, conn)?"1.1":"1.0";
2116 /* initialize a dynamic send-buffer */
2117 req_buffer = Curl_add_buffer_init();
2120 return CURLE_OUT_OF_MEMORY;
2122 /* add the main request stuff */
2123 /* GET/HEAD/POST/PUT */
2124 result = Curl_add_bufferf(req_buffer, "%s ", request);
2129 if(paste_ftp_userpwd)
2130 result = Curl_add_bufferf(req_buffer, "ftp://%s:%s@%s",
2131 conn->user, conn->passwd,
2132 ppath + sizeof("ftp://") - 1);
2134 result = Curl_add_buffer(req_buffer, ppath, strlen(ppath));
2139 Curl_add_bufferf(req_buffer,
2140 "%s" /* ftp typecode (;type=x) */
2141 " HTTP/%s\r\n" /* HTTP version */
2142 "%s" /* proxyuserpwd */
2145 "%s" /* user agent */
2149 "%s" /* accept-encoding */
2151 "%s" /* Proxy-Connection */
2152 "%s",/* transfer-encoding */
2156 conn->allocptr.proxyuserpwd?
2157 conn->allocptr.proxyuserpwd:"",
2158 conn->allocptr.userpwd?conn->allocptr.userpwd:"",
2159 (data->state.use_range && conn->allocptr.rangeline)?
2160 conn->allocptr.rangeline:"",
2161 (data->set.str[STRING_USERAGENT] &&
2162 *data->set.str[STRING_USERAGENT] &&
2163 conn->allocptr.uagent)?
2164 conn->allocptr.uagent:"",
2165 (conn->allocptr.host?conn->allocptr.host:""),
2166 http->p_accept?http->p_accept:"",
2167 conn->allocptr.te?conn->allocptr.te:"",
2168 (data->set.str[STRING_ENCODING] &&
2169 *data->set.str[STRING_ENCODING] &&
2170 conn->allocptr.accept_encoding)?
2171 conn->allocptr.accept_encoding:"",
2172 (data->change.referer && conn->allocptr.ref)?
2173 conn->allocptr.ref:"" /* Referer: <data> */,
2174 (conn->bits.httpproxy &&
2175 !conn->bits.tunnel_proxy &&
2176 !Curl_checkheaders(data, "Proxy-Connection:"))?
2177 "Proxy-Connection: Keep-Alive\r\n":"",
2182 * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM
2183 * with basic and digest, it will be freed anyway by the next request
2186 Curl_safefree (conn->allocptr.userpwd);
2187 conn->allocptr.userpwd = NULL;
2192 #if !defined(CURL_DISABLE_COOKIES)
2193 if(data->cookies || addcookies) {
2194 struct Cookie *co=NULL; /* no cookies from start */
2198 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
2199 co = Curl_cookie_getlist(data->cookies,
2200 conn->allocptr.cookiehost?
2201 conn->allocptr.cookiehost:host,
2203 (conn->handler->protocol&CURLPROTO_HTTPS)?
2205 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
2208 struct Cookie *store=co;
2209 /* now loop through all cookies that matched */
2213 result = Curl_add_bufferf(req_buffer, "Cookie: ");
2217 result = Curl_add_bufferf(req_buffer,
2218 "%s%s=%s", count?"; ":"",
2219 co->name, co->value);
2224 co = co->next; /* next cookie please */
2226 Curl_cookie_freelist(store, FALSE); /* free the cookie list */
2228 if(addcookies && (CURLE_OK == result)) {
2230 result = Curl_add_bufferf(req_buffer, "Cookie: ");
2231 if(CURLE_OK == result) {
2232 result = Curl_add_bufferf(req_buffer, "%s%s",
2238 if(count && (CURLE_OK == result))
2239 result = Curl_add_buffer(req_buffer, "\r\n", 2);
2246 if(data->set.timecondition) {
2247 result = Curl_add_timecondition(data, req_buffer);
2252 result = Curl_add_custom_headers(conn, req_buffer);
2256 http->postdata = NULL; /* nothing to post at this point */
2257 Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
2259 /* If 'authdone' is FALSE, we must not set the write socket index to the
2260 Curl_transfer() call below, as we're not ready to actually upload any
2265 case HTTPREQ_POST_FORM:
2266 if(!http->sendit || conn->bits.authneg) {
2267 /* nothing to post! */
2268 result = Curl_add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
2272 result = Curl_add_buffer_send(req_buffer, conn,
2273 &data->info.request_size, 0, FIRSTSOCKET);
2275 failf(data, "Failed sending POST request");
2277 /* setup variables for the upcoming transfer */
2278 Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
2283 if(Curl_FormInit(&http->form, http->sendit)) {
2284 failf(data, "Internal HTTP POST error!");
2285 return CURLE_HTTP_POST_ERROR;
2288 /* Get the currently set callback function pointer and store that in the
2289 form struct since we might want the actual user-provided callback later
2290 on. The conn->fread_func pointer itself will be changed for the
2291 multipart case to the function that returns a multipart formatted
2293 http->form.fread_func = conn->fread_func;
2295 /* Set the read function to read from the generated form data */
2296 conn->fread_func = (curl_read_callback)Curl_FormReader;
2297 conn->fread_in = &http->form;
2299 http->sending = HTTPSEND_BODY;
2301 if(!data->req.upload_chunky &&
2302 !Curl_checkheaders(data, "Content-Length:")) {
2303 /* only add Content-Length if not uploading chunked */
2304 result = Curl_add_bufferf(req_buffer,
2305 "Content-Length: %" FORMAT_OFF_T "\r\n",
2311 result = expect100(data, conn, req_buffer);
2317 /* Get Content-Type: line from Curl_formpostheader.
2320 size_t linelength=0;
2321 contentType = Curl_formpostheader((void *)&http->form,
2324 failf(data, "Could not get Content-Type header line!");
2325 return CURLE_HTTP_POST_ERROR;
2328 result = Curl_add_buffer(req_buffer, contentType, linelength);
2333 /* make the request end in a true CRLF */
2334 result = Curl_add_buffer(req_buffer, "\r\n", 2);
2338 /* set upload size to the progress meter */
2339 Curl_pgrsSetUploadSize(data, http->postsize);
2341 /* fire away the whole request to the server */
2342 result = Curl_add_buffer_send(req_buffer, conn,
2343 &data->info.request_size, 0, FIRSTSOCKET);
2345 failf(data, "Failed sending POST request");
2347 /* setup variables for the upcoming transfer */
2348 Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2349 &http->readbytecount, FIRSTSOCKET,
2350 &http->writebytecount);
2353 Curl_formclean(&http->sendit); /* free that whole lot */
2357 /* convert the form data */
2358 result = Curl_convert_form(data, http->sendit);
2360 Curl_formclean(&http->sendit); /* free that whole lot */
2366 case HTTPREQ_PUT: /* Let's PUT the data to the server! */
2368 if(conn->bits.authneg)
2371 postsize = data->set.infilesize;
2373 if((postsize != -1) && !data->req.upload_chunky &&
2374 !Curl_checkheaders(data, "Content-Length:")) {
2375 /* only add Content-Length if not uploading chunked */
2376 result = Curl_add_bufferf(req_buffer,
2377 "Content-Length: %" FORMAT_OFF_T "\r\n",
2383 result = expect100(data, conn, req_buffer);
2387 result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */
2391 /* set the upload size to the progress meter */
2392 Curl_pgrsSetUploadSize(data, postsize);
2394 /* this sends the buffer and frees all the buffer resources */
2395 result = Curl_add_buffer_send(req_buffer, conn,
2396 &data->info.request_size, 0, FIRSTSOCKET);
2398 failf(data, "Failed sending PUT request");
2400 /* prepare for transfer */
2401 Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2402 &http->readbytecount, postsize?FIRSTSOCKET:-1,
2403 postsize?&http->writebytecount:NULL);
2409 /* this is the simple POST, using x-www-form-urlencoded style */
2411 if(conn->bits.authneg)
2414 /* figure out the size of the postfields */
2415 postsize = (data->set.postfieldsize != -1)?
2416 data->set.postfieldsize:
2417 (data->set.postfields? (curl_off_t)strlen(data->set.postfields):-1);
2419 if(!data->req.upload_chunky) {
2420 /* We only set Content-Length and allow a custom Content-Length if
2421 we don't upload data chunked, as RFC2616 forbids us to set both
2422 kinds of headers (Transfer-Encoding: chunked and Content-Length) */
2424 if(conn->bits.authneg || !Curl_checkheaders(data, "Content-Length:")) {
2425 /* we allow replacing this header if not during auth negotiation,
2426 although it isn't very wise to actually set your own */
2427 result = Curl_add_bufferf(req_buffer,
2428 "Content-Length: %" FORMAT_OFF_T"\r\n",
2435 if(!Curl_checkheaders(data, "Content-Type:")) {
2436 result = Curl_add_bufferf(req_buffer,
2437 "Content-Type: application/"
2438 "x-www-form-urlencoded\r\n");
2443 /* For really small posts we don't use Expect: headers at all, and for
2444 the somewhat bigger ones we allow the app to disable it. Just make
2445 sure that the expect100header is always set to the preferred value
2447 ptr = Curl_checkheaders(data, "Expect:");
2449 data->state.expect100header =
2450 Curl_compareheader(ptr, "Expect:", "100-continue");
2452 else if(postsize > TINY_INITIAL_POST_SIZE || postsize < 0) {
2453 result = expect100(data, conn, req_buffer);
2458 data->state.expect100header = FALSE;
2460 if(data->set.postfields) {
2462 if(!data->state.expect100header &&
2463 (postsize < MAX_INITIAL_POST_SIZE)) {
2464 /* if we don't use expect: 100 AND
2465 postsize is less than MAX_INITIAL_POST_SIZE
2467 then append the post data to the HTTP request header. This limit
2468 is no magic limit but only set to prevent really huge POSTs to
2469 get the data duplicated with malloc() and family. */
2471 result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2475 if(!data->req.upload_chunky) {
2476 /* We're not sending it 'chunked', append it to the request
2477 already now to reduce the number if send() calls */
2478 result = Curl_add_buffer(req_buffer, data->set.postfields,
2480 included_body = postsize;
2483 /* Append the POST data chunky-style */
2484 result = Curl_add_bufferf(req_buffer, "%x\r\n", (int)postsize);
2485 if(CURLE_OK == result)
2486 result = Curl_add_buffer(req_buffer, data->set.postfields,
2488 if(CURLE_OK == result)
2489 result = Curl_add_buffer(req_buffer,
2490 "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7);
2491 /* CR LF 0 CR LF CR LF */
2492 included_body = postsize + 7;
2496 /* Make sure the progress information is accurate */
2497 Curl_pgrsSetUploadSize(data, postsize);
2500 /* A huge POST coming up, do data separate from the request */
2501 http->postsize = postsize;
2502 http->postdata = data->set.postfields;
2504 http->sending = HTTPSEND_BODY;
2506 conn->fread_func = (curl_read_callback)readmoredata;
2507 conn->fread_in = (void *)conn;
2509 /* set the upload size to the progress meter */
2510 Curl_pgrsSetUploadSize(data, http->postsize);
2512 result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2518 result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2522 if(data->req.upload_chunky && conn->bits.authneg) {
2523 /* Chunky upload is selected and we're negotiating auth still, send
2525 result = Curl_add_buffer(req_buffer,
2526 "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7);
2527 /* CR LF 0 CR LF CR LF */
2532 else if(data->set.postfieldsize) {
2533 /* set the upload size to the progress meter */
2534 Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
2536 /* set the pointer to mark that we will send the post body using the
2537 read callback, but only if we're not in authenticate
2539 if(!conn->bits.authneg) {
2540 http->postdata = (char *)&http->postdata;
2541 http->postsize = postsize;
2545 /* issue the request */
2546 result = Curl_add_buffer_send(req_buffer, conn, &data->info.request_size,
2547 (size_t)included_body, FIRSTSOCKET);
2550 failf(data, "Failed sending HTTP POST request");
2552 Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2553 &http->readbytecount, http->postdata?FIRSTSOCKET:-1,
2554 http->postdata?&http->writebytecount:NULL);
2558 result = Curl_add_buffer(req_buffer, "\r\n", 2);
2562 /* issue the request */
2563 result = Curl_add_buffer_send(req_buffer, conn,
2564 &data->info.request_size, 0, FIRSTSOCKET);
2567 failf(data, "Failed sending HTTP request");
2569 /* HTTP GET/HEAD download: */
2570 Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
2571 http->postdata?FIRSTSOCKET:-1,
2572 http->postdata?&http->writebytecount:NULL);
2577 if(http->writebytecount) {
2578 /* if a request-body has been sent off, we make sure this progress is noted
2580 Curl_pgrsSetUploadCounter(data, http->writebytecount);
2581 if(Curl_pgrsUpdate(conn))
2582 result = CURLE_ABORTED_BY_CALLBACK;
2584 if(http->writebytecount >= postsize) {
2585 /* already sent the entire request body, mark the "upload" as
2587 infof(data, "upload completely sent off: %" FORMAT_OFF_T " out of "
2588 "%" FORMAT_OFF_T " bytes\n",
2589 http->writebytecount, postsize);
2590 data->req.upload_done = TRUE;
2591 data->req.keepon &= ~KEEP_SEND; /* we're done writing */
2592 data->req.exp100 = EXP100_SEND_DATA; /* already sent */
2602 * Returns TRUE if member of the list matches prefix of string
2605 checkhttpprefix(struct SessionHandle *data,
2608 struct curl_slist *head = data->set.http200aliases;
2610 #ifdef CURL_DOES_CONVERSIONS
2611 /* convert from the network encoding using a scratch area */
2612 char *scratch = strdup(s);
2613 if(NULL == scratch) {
2614 failf (data, "Failed to allocate memory for conversion!");
2615 return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
2617 if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
2618 /* Curl_convert_from_network calls failf if unsuccessful */
2620 return FALSE; /* can't return CURLE_foobar so return FALSE */
2623 #endif /* CURL_DOES_CONVERSIONS */
2626 if(checkprefix(head->data, s)) {
2633 if(!rc && (checkprefix("HTTP/", s)))
2636 #ifdef CURL_DOES_CONVERSIONS
2638 #endif /* CURL_DOES_CONVERSIONS */
2642 #ifndef CURL_DISABLE_RTSP
2644 checkrtspprefix(struct SessionHandle *data,
2648 #ifdef CURL_DOES_CONVERSIONS
2649 /* convert from the network encoding using a scratch area */
2650 char *scratch = strdup(s);
2651 if(NULL == scratch) {
2652 failf (data, "Failed to allocate memory for conversion!");
2653 return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
2655 if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
2656 /* Curl_convert_from_network calls failf if unsuccessful */
2658 return FALSE; /* can't return CURLE_foobar so return FALSE */
2662 (void)data; /* unused */
2663 #endif /* CURL_DOES_CONVERSIONS */
2664 if(checkprefix("RTSP/", s))
2669 #endif /* CURL_DISABLE_RTSP */
2672 checkprotoprefix(struct SessionHandle *data, struct connectdata *conn,
2675 #ifndef CURL_DISABLE_RTSP
2676 if(conn->handler->protocol & CURLPROTO_RTSP)
2677 return checkrtspprefix(data, s);
2680 #endif /* CURL_DISABLE_RTSP */
2682 return checkhttpprefix(data, s);
2686 * header_append() copies a chunk of data to the end of the already received
2687 * header. We make sure that the full string fit in the allocated header
2688 * buffer, or else we enlarge it.
2690 static CURLcode header_append(struct SessionHandle *data,
2691 struct SingleRequest *k,
2694 if(k->hbuflen + length >= data->state.headersize) {
2695 /* We enlarge the header buffer as it is too small */
2700 if(k->hbuflen + length > CURL_MAX_HTTP_HEADER) {
2701 /* The reason to have a max limit for this is to avoid the risk of a bad
2702 server feeding libcurl with a never-ending header that will cause
2703 reallocs infinitely */
2704 failf (data, "Avoided giant realloc for header (max is %d)!",
2705 CURL_MAX_HTTP_HEADER);
2706 return CURLE_OUT_OF_MEMORY;
2709 newsize=CURLMAX((k->hbuflen+ length)*3/2, data->state.headersize*2);
2710 hbufp_index = k->hbufp - data->state.headerbuff;
2711 newbuff = realloc(data->state.headerbuff, newsize);
2713 failf (data, "Failed to alloc memory for big header!");
2714 return CURLE_OUT_OF_MEMORY;
2716 data->state.headersize=newsize;
2717 data->state.headerbuff = newbuff;
2718 k->hbufp = data->state.headerbuff + hbufp_index;
2720 memcpy(k->hbufp, k->str_start, length);
2722 k->hbuflen += length;
2730 * Read any HTTP header lines from the server and pass them to the client app.
2732 CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
2733 struct connectdata *conn,
2738 struct SingleRequest *k = &data->req;
2740 /* header line within buffer loop */
2746 /* str_start is start of line within buf */
2747 k->str_start = k->str;
2749 /* data is in network encoding so use 0x0a instead of '\n' */
2750 k->end_ptr = memchr(k->str_start, 0x0a, *nread);
2753 /* Not a complete header line within buffer, append the data to
2754 the end of the headerbuff. */
2755 result = header_append(data, k, *nread);
2759 if(!k->headerline && (k->hbuflen>5)) {
2760 /* make a first check that this looks like a protocol header */
2761 if(!checkprotoprefix(data, conn, data->state.headerbuff)) {
2762 /* this is not the beginning of a protocol first header line */
2764 k->badheader = HEADER_ALLBAD;
2769 break; /* read more and try again */
2772 /* decrease the size of the remaining (supposed) header line */
2773 rest_length = (k->end_ptr - k->str)+1;
2774 *nread -= (ssize_t)rest_length;
2776 k->str = k->end_ptr + 1; /* move past new line */
2778 full_length = k->str - k->str_start;
2780 result = header_append(data, k, full_length);
2784 k->end_ptr = k->hbufp;
2785 k->p = data->state.headerbuff;
2788 * We now have a FULL header line that p points to
2791 if(!k->headerline) {
2792 /* the first read header */
2793 if((k->hbuflen>5) &&
2794 !checkprotoprefix(data, conn, data->state.headerbuff)) {
2795 /* this is not the beginning of a protocol first header line */
2798 /* since there's more, this is a partial bad header */
2799 k->badheader = HEADER_PARTHEADER;
2801 /* this was all we read so it's all a bad header */
2802 k->badheader = HEADER_ALLBAD;
2803 *nread = (ssize_t)rest_length;
2809 /* headers are in network encoding so
2810 use 0x0a and 0x0d instead of '\n' and '\r' */
2811 if((0x0a == *k->p) || (0x0d == *k->p)) {
2813 /* Zero-length header line means end of headers! */
2815 #ifdef CURL_DOES_CONVERSIONS
2817 *k->p = '\r'; /* replace with CR in host encoding */
2818 k->p++; /* pass the CR byte */
2821 *k->p = '\n'; /* replace with LF in host encoding */
2822 k->p++; /* pass the LF byte */
2826 k->p++; /* pass the \r byte */
2828 k->p++; /* pass the \n byte */
2829 #endif /* CURL_DOES_CONVERSIONS */
2831 if(100 <= k->httpcode && 199 >= k->httpcode) {
2833 * We have made a HTTP PUT or POST and this is 1.1-lingo
2834 * that tells us that the server is OK with this and ready
2835 * to receive the data.
2836 * However, we'll get more headers now so we must get
2837 * back into the header-parsing state!
2840 k->headerline = 0; /* restart the header line counter */
2842 /* if we did wait for this do enable write now! */
2844 k->exp100 = EXP100_SEND_DATA;
2845 k->keepon |= KEEP_SEND;
2849 k->header = FALSE; /* no more header to parse! */
2851 if((k->size == -1) && !k->chunk && !conn->bits.close &&
2852 (conn->httpversion >= 11) &&
2853 !(conn->handler->protocol & CURLPROTO_RTSP)) {
2854 /* On HTTP 1.1, when connection is not to get closed, but no
2855 Content-Length nor Content-Encoding chunked have been
2856 received, according to RFC2616 section 4.4 point 5, we
2857 assume that the server will close the connection to
2858 signal the end of the document. */
2859 infof(data, "no chunk, no close, no size. Assume close to "
2861 conn->bits.close = TRUE;
2866 * When all the headers have been parsed, see if we should give
2867 * up and return an error.
2869 if(http_should_fail(conn)) {
2870 failf (data, "The requested URL returned error: %d",
2872 return CURLE_HTTP_RETURNED_ERROR;
2875 /* now, only output this if the header AND body are requested:
2877 writetype = CLIENTWRITE_HEADER;
2878 if(data->set.include_header)
2879 writetype |= CLIENTWRITE_BODY;
2881 headerlen = k->p - data->state.headerbuff;
2883 result = Curl_client_write(conn, writetype,
2884 data->state.headerbuff,
2889 data->info.header_size += (long)headerlen;
2890 data->req.headerbytecount += (long)headerlen;
2892 data->req.deductheadercount =
2893 (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
2895 if(!*stop_reading) {
2896 /* Curl_http_auth_act() checks what authentication methods
2897 * that are available and decides which one (if any) to
2898 * use. It will set 'newurl' if an auth method was picked. */
2899 result = Curl_http_auth_act(conn);
2904 if(k->httpcode >= 300) {
2905 if((!conn->bits.authneg) && !conn->bits.close &&
2906 !conn->bits.rewindaftersend) {
2908 * General treatment of errors when about to send data. Including :
2909 * "417 Expectation Failed", while waiting for 100-continue.
2911 * The check for close above is done simply because of something
2912 * else has already deemed the connection to get closed then
2913 * something else should've considered the big picture and we
2916 * rewindaftersend indicates that something has told libcurl to
2917 * continue sending even if it gets discarded
2920 switch(data->set.httpreq) {
2923 case HTTPREQ_POST_FORM:
2924 /* We got an error response. If this happened before the whole
2925 * request body has been sent we stop sending and mark the
2926 * connection for closure after we've read the entire response.
2928 if(!k->upload_done) {
2929 infof(data, "HTTP error before end of send, stop sending\n");
2930 conn->bits.close = TRUE; /* close after this */
2931 k->upload_done = TRUE;
2932 k->keepon &= ~KEEP_SEND; /* don't send */
2933 if(data->state.expect100header)
2934 k->exp100 = EXP100_FAILED;
2938 default: /* default label present to avoid compiler warnings */
2944 if(conn->bits.rewindaftersend) {
2945 /* We rewind after a complete send, so thus we continue
2947 infof(data, "Keep sending data to get tossed away!\n");
2948 k->keepon |= KEEP_SEND;
2954 * really end-of-headers.
2956 * If we requested a "no body", this is a good time to get
2957 * out and return home.
2959 if(data->set.opt_no_body)
2960 *stop_reading = TRUE;
2962 /* If we know the expected size of this document, we set the
2963 maximum download size to the size of the expected
2964 document or else, we won't know when to stop reading!
2966 Note that we set the download maximum even if we read a
2967 "Connection: close" header, to make sure that
2968 "Content-Length: 0" still prevents us from attempting to
2969 read the (missing) response-body.
2971 /* According to RFC2616 section 4.4, we MUST ignore
2972 Content-Length: headers if we are now receiving data
2973 using chunked Transfer-Encoding.
2976 k->maxdownload = k->size = -1;
2979 /* We do this operation even if no_body is true, since this
2980 data might be retrieved later with curl_easy_getinfo()
2981 and its CURLINFO_CONTENT_LENGTH_DOWNLOAD option. */
2983 Curl_pgrsSetDownloadSize(data, k->size);
2984 k->maxdownload = k->size;
2987 /* If max download size is *zero* (nothing) we already
2988 have nothing and can safely return ok now! */
2989 if(0 == k->maxdownload)
2990 *stop_reading = TRUE;
2993 /* we make sure that this socket isn't read more now */
2994 k->keepon &= ~KEEP_RECV;
2997 if(data->set.verbose)
2998 Curl_debug(data, CURLINFO_HEADER_IN,
2999 k->str_start, headerlen, conn);
3000 break; /* exit header line loop */
3003 /* We continue reading headers, so reset the line-based
3004 header parsing variables hbufp && hbuflen */
3005 k->hbufp = data->state.headerbuff;
3011 * Checks for special headers coming up.
3014 if(!k->headerline++) {
3015 /* This is the first header, it MUST be the error code line
3016 or else we consider this to be the body right away! */
3017 int httpversion_major;
3018 int rtspversion_major;
3020 #ifdef CURL_DOES_CONVERSIONS
3021 #define HEADER1 scratch
3022 #define SCRATCHSIZE 21
3024 char scratch[SCRATCHSIZE+1]; /* "HTTP/major.minor 123" */
3025 /* We can't really convert this yet because we
3026 don't know if it's the 1st header line or the body.
3027 So we do a partial conversion into a scratch area,
3028 leaving the data at k->p as-is.
3030 strncpy(&scratch[0], k->p, SCRATCHSIZE);
3031 scratch[SCRATCHSIZE] = 0; /* null terminate */
3032 res = Curl_convert_from_network(data,
3036 /* Curl_convert_from_network calls failf if unsuccessful */
3039 #define HEADER1 k->p /* no conversion needed, just use k->p */
3040 #endif /* CURL_DOES_CONVERSIONS */
3042 if(conn->handler->protocol & CURLPROTO_HTTP) {
3043 nc = sscanf(HEADER1,
3049 conn->httpversion += 10 * httpversion_major;
3052 /* this is the real world, not a Nirvana
3053 NCSA 1.5.x returns this crap when asked for HTTP/1.1
3055 nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode);
3056 conn->httpversion = 10;
3058 /* If user has set option HTTP200ALIASES,
3059 compare header line against list of aliases
3062 if(checkhttpprefix(data, k->p)) {
3065 conn->httpversion = 10;
3070 else if(conn->handler->protocol & CURLPROTO_RTSP) {
3071 nc = sscanf(HEADER1,
3077 conn->rtspversion += 10 * rtspversion_major;
3078 conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
3081 /* TODO: do we care about the other cases here? */
3087 data->info.httpcode = k->httpcode;
3089 data->info.httpversion = conn->httpversion;
3090 if(!data->state.httpversion ||
3091 data->state.httpversion > conn->httpversion)
3092 /* store the lowest server version we encounter */
3093 data->state.httpversion = conn->httpversion;
3096 * This code executes as part of processing the header. As a
3097 * result, it's not totally clear how to interpret the
3098 * response code yet as that depends on what other headers may
3099 * be present. 401 and 407 may be errors, but may be OK
3100 * depending on how authentication is working. Other codes
3101 * are definitely errors, so give up here.
3103 if(data->set.http_fail_on_error && (k->httpcode >= 400) &&
3104 ((k->httpcode != 401) || !conn->bits.user_passwd) &&
3105 ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) {
3107 if(data->state.resume_from &&
3108 (data->set.httpreq==HTTPREQ_GET) &&
3109 (k->httpcode == 416)) {
3110 /* "Requested Range Not Satisfiable", just proceed and
3111 pretend this is no error */
3114 /* serious error, go home! */
3115 failf (data, "The requested URL returned error: %d",
3117 return CURLE_HTTP_RETURNED_ERROR;
3121 if(conn->httpversion == 10) {
3122 /* Default action for HTTP/1.0 must be to close, unless
3123 we get one of those fancy headers that tell us the
3124 server keeps it open for us! */
3125 infof(data, "HTTP 1.0, assume close after body\n");
3126 conn->bits.close = TRUE;
3128 else if(conn->httpversion >= 11 &&
3129 !conn->bits.close) {
3130 /* If HTTP version is >= 1.1 and connection is persistent
3131 server supports pipelining. */
3133 "HTTP 1.1 or later with persistent connection, "
3134 "pipelining supported\n"));
3135 conn->server_supports_pipelining = TRUE;
3138 switch(k->httpcode) {
3140 /* (quote from RFC2616, section 10.2.5): The server has
3141 * fulfilled the request but does not need to return an
3142 * entity-body ... The 204 response MUST NOT include a
3143 * message-body, and thus is always terminated by the first
3144 * empty line after the header fields. */
3147 /* (quote from RFC2616, section 10.3.5): The 304 response
3148 * MUST NOT contain a message-body, and thus is always
3149 * terminated by the first empty line after the header
3151 if(data->set.timecondition)
3152 data->info.timecond = TRUE;
3155 k->ignorecl = TRUE; /* ignore Content-Length headers */
3163 k->header = FALSE; /* this is not a header line */
3168 result = Curl_convert_from_network(data, k->p, strlen(k->p));
3169 /* Curl_convert_from_network calls failf if unsuccessful */
3173 /* Check for Content-Length: header lines to get size */
3174 if(!k->ignorecl && !data->set.ignorecl &&
3175 checkprefix("Content-Length:", k->p)) {
3176 curl_off_t contentlength = curlx_strtoofft(k->p+15, NULL, 10);
3177 if(data->set.max_filesize &&
3178 contentlength > data->set.max_filesize) {
3179 failf(data, "Maximum file size exceeded");
3180 return CURLE_FILESIZE_EXCEEDED;
3182 if(contentlength >= 0) {
3183 k->size = contentlength;
3184 k->maxdownload = k->size;
3185 /* we set the progress download size already at this point
3186 just to make it easier for apps/callbacks to extract this
3187 info as soon as possible */
3188 Curl_pgrsSetDownloadSize(data, k->size);
3191 /* Negative Content-Length is really odd, and we know it
3192 happens for example when older Apache servers send large
3194 conn->bits.close = TRUE;
3195 infof(data, "Negative content-length: %" FORMAT_OFF_T
3196 ", closing after transfer\n", contentlength);
3199 /* check for Content-Type: header lines to get the MIME-type */
3200 else if(checkprefix("Content-Type:", k->p)) {
3201 char *contenttype = copy_header_value(k->p);
3203 return CURLE_OUT_OF_MEMORY;
3205 /* ignore empty data */
3208 Curl_safefree(data->info.contenttype);
3209 data->info.contenttype = contenttype;
3212 else if((conn->httpversion == 10) &&
3213 conn->bits.httpproxy &&
3214 Curl_compareheader(k->p,
3215 "Proxy-Connection:", "keep-alive")) {
3217 * When a HTTP/1.0 reply comes when using a proxy, the
3218 * 'Proxy-Connection: keep-alive' line tells us the
3219 * connection will be kept alive for our pleasure.
3220 * Default action for 1.0 is to close.
3222 conn->bits.close = FALSE; /* don't close when done */
3223 infof(data, "HTTP/1.0 proxy connection set to keep alive!\n");
3225 else if((conn->httpversion == 11) &&
3226 conn->bits.httpproxy &&
3227 Curl_compareheader(k->p,
3228 "Proxy-Connection:", "close")) {
3230 * We get a HTTP/1.1 response from a proxy and it says it'll
3231 * close down after this transfer.
3233 conn->bits.close = TRUE; /* close when done */
3234 infof(data, "HTTP/1.1 proxy connection set close!\n");
3236 else if((conn->httpversion == 10) &&
3237 Curl_compareheader(k->p, "Connection:", "keep-alive")) {
3239 * A HTTP/1.0 reply with the 'Connection: keep-alive' line
3240 * tells us the connection will be kept alive for our
3241 * pleasure. Default action for 1.0 is to close.
3243 * [RFC2068, section 19.7.1] */
3244 conn->bits.close = FALSE; /* don't close when done */
3245 infof(data, "HTTP/1.0 connection set to keep alive!\n");
3247 else if(Curl_compareheader(k->p, "Connection:", "close")) {
3249 * [RFC 2616, section 8.1.2.1]
3250 * "Connection: close" is HTTP/1.1 language and means that
3251 * the connection will close when this request has been
3254 conn->bits.close = TRUE; /* close when done */
3256 else if(checkprefix("Transfer-Encoding:", k->p)) {
3257 /* One or more encodings. We check for chunked and/or a compression
3260 * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding
3261 * means that the server will send a series of "chunks". Each
3262 * chunk starts with line with info (including size of the
3263 * coming block) (terminated with CRLF), then a block of data
3264 * with the previously mentioned size. There can be any amount
3265 * of chunks, and a chunk-data set to zero signals the
3270 /* Find the first non-space letter */
3274 /* skip whitespaces and commas */
3275 while(*start && (ISSPACE(*start) || (*start == ',')))
3278 if(checkprefix("chunked", start)) {
3279 k->chunk = TRUE; /* chunks coming our way */
3281 /* init our chunky engine */
3282 Curl_httpchunk_init(conn);
3287 if(k->auto_decoding)
3288 /* TODO: we only support the first mentioned compression for now */
3291 if(checkprefix("identity", start)) {
3292 k->auto_decoding = IDENTITY;
3295 else if(checkprefix("deflate", start)) {
3296 k->auto_decoding = DEFLATE;
3299 else if(checkprefix("gzip", start)) {
3300 k->auto_decoding = GZIP;
3303 else if(checkprefix("x-gzip", start)) {
3304 k->auto_decoding = GZIP;
3307 else if(checkprefix("compress", start)) {
3308 k->auto_decoding = COMPRESS;
3311 else if(checkprefix("x-compress", start)) {
3312 k->auto_decoding = COMPRESS;
3322 else if(checkprefix("Content-Encoding:", k->p) &&
3323 data->set.str[STRING_ENCODING]) {
3325 * Process Content-Encoding. Look for the values: identity,
3326 * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
3327 * x-compress are the same as gzip and compress. (Sec 3.5 RFC
3328 * 2616). zlib cannot handle compress. However, errors are
3329 * handled further down when the response body is processed
3333 /* Find the first non-space letter */
3335 while(*start && ISSPACE(*start))
3338 /* Record the content-encoding for later use */
3339 if(checkprefix("identity", start))
3340 k->auto_decoding = IDENTITY;
3341 else if(checkprefix("deflate", start))
3342 k->auto_decoding = DEFLATE;
3343 else if(checkprefix("gzip", start)
3344 || checkprefix("x-gzip", start))
3345 k->auto_decoding = GZIP;
3346 else if(checkprefix("compress", start)
3347 || checkprefix("x-compress", start))
3348 k->auto_decoding = COMPRESS;
3350 else if(checkprefix("Content-Range:", k->p)) {
3351 /* Content-Range: bytes [num]-
3352 Content-Range: bytes: [num]-
3353 Content-Range: [num]-
3355 The second format was added since Sun's webserver
3356 JavaWebServer/1.1.1 obviously sends the header this way!
3357 The third added since some servers use that!
3360 char *ptr = k->p + 14;
3362 /* Move forward until first digit */
3363 while(*ptr && !ISDIGIT(*ptr))
3366 k->offset = curlx_strtoofft(ptr, NULL, 10);
3368 if(data->state.resume_from == k->offset)
3369 /* we asked for a resume and we got it */
3370 k->content_range = TRUE;
3372 #if !defined(CURL_DISABLE_COOKIES)
3373 else if(data->cookies &&
3374 checkprefix("Set-Cookie:", k->p)) {
3375 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
3376 CURL_LOCK_ACCESS_SINGLE);
3377 Curl_cookie_add(data,
3378 data->cookies, TRUE, k->p+11,
3379 /* If there is a custom-set Host: name, use it
3380 here, or else use real peer host name. */
3381 conn->allocptr.cookiehost?
3382 conn->allocptr.cookiehost:conn->host.name,
3384 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
3387 else if(checkprefix("Last-Modified:", k->p) &&
3388 (data->set.timecondition || data->set.get_filetime) ) {
3389 time_t secs=time(NULL);
3390 k->timeofdoc = curl_getdate(k->p+strlen("Last-Modified:"),
3392 if(data->set.get_filetime)
3393 data->info.filetime = (long)k->timeofdoc;
3395 else if((checkprefix("WWW-Authenticate:", k->p) &&
3396 (401 == k->httpcode)) ||
3397 (checkprefix("Proxy-authenticate:", k->p) &&
3398 (407 == k->httpcode))) {
3399 result = Curl_http_input_auth(conn, k->httpcode, k->p);
3403 else if((k->httpcode >= 300 && k->httpcode < 400) &&
3404 checkprefix("Location:", k->p) &&
3405 !data->req.location) {
3406 /* this is the URL that the server advises us to use instead */
3407 char *location = copy_header_value(k->p);
3409 return CURLE_OUT_OF_MEMORY;
3411 /* ignore empty data */
3414 data->req.location = location;
3416 if(data->set.http_follow_location) {
3417 DEBUGASSERT(!data->req.newurl);
3418 data->req.newurl = strdup(data->req.location); /* clone */
3419 if(!data->req.newurl)
3420 return CURLE_OUT_OF_MEMORY;
3422 /* some cases of POST and PUT etc needs to rewind the data
3423 stream at this point */
3424 result = http_perhapsrewind(conn);
3430 else if(conn->handler->protocol & CURLPROTO_RTSP) {
3431 result = Curl_rtsp_parseheader(conn, k->p);
3437 * End of header-checks. Write them to the client.
3440 writetype = CLIENTWRITE_HEADER;
3441 if(data->set.include_header)
3442 writetype |= CLIENTWRITE_BODY;
3444 if(data->set.verbose)
3445 Curl_debug(data, CURLINFO_HEADER_IN,
3446 k->p, (size_t)k->hbuflen, conn);
3448 result = Curl_client_write(conn, writetype, k->p, k->hbuflen);
3452 data->info.header_size += (long)k->hbuflen;
3453 data->req.headerbytecount += (long)k->hbuflen;
3455 /* reset hbufp pointer && hbuflen */
3456 k->hbufp = data->state.headerbuff;
3459 while(!*stop_reading && *k->str); /* header line within buffer */
3461 /* We might have reached the end of the header part here, but
3462 there might be a non-header part left in the end of the read
3468 #endif /* CURL_DISABLE_HTTP */