1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2008, 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 * $Id: http.c,v 1.1.1.1 2008-09-23 16:32:05 hoffman Exp $
22 ***************************************************************************/
26 #ifndef CURL_DISABLE_HTTP
27 /* -- WIN32 approved -- */
38 #ifdef HAVE_SYS_SOCKET_H
39 #include <sys/socket.h>
41 #ifdef HAVE_NETINET_IN_H
42 #include <netinet/in.h>
44 #ifdef HAVE_SYS_TIME_H
49 #ifdef TIME_WITH_SYS_TIME
60 #ifdef HAVE_ARPA_INET_H
61 #include <arpa/inet.h>
66 #ifdef HAVE_SYS_IOCTL_H
67 #include <sys/ioctl.h>
71 #ifdef HAVE_SYS_PARAM_H
72 #include <sys/param.h>
78 #include <curl/curl.h>
81 #include "easyif.h" /* for Curl_convert_... prototypes */
84 #include "curl_base64.h"
88 #include "http_digest.h"
89 #include "http_ntlm.h"
90 #include "http_negotiate.h"
97 #include "parsedate.h" /* for the week day and month names */
98 #include "strtoofft.h"
101 #define _MPRINTF_REPLACE /* use our functions only */
102 #include <curl/mprintf.h>
104 /* The last #include file should be: */
105 #include "memdebug.h"
107 /* Default proxy timeout in milliseconds */
108 #define PROXY_TIMEOUT (3600*1000)
111 * Forward declarations.
114 static int http_getsock_do(struct connectdata
*conn
,
115 curl_socket_t
*socks
,
117 static CURLcode
https_connecting(struct connectdata
*conn
, bool *done
);
119 static int https_getsock(struct connectdata
*conn
,
120 curl_socket_t
*socks
,
125 * HTTP handler interface.
127 const struct Curl_handler Curl_handler_http
= {
129 ZERO_NULL
, /* setup_connection */
130 Curl_http
, /* do_it */
131 Curl_http_done
, /* done */
132 ZERO_NULL
, /* do_more */
133 Curl_http_connect
, /* connect_it */
134 ZERO_NULL
, /* connecting */
135 ZERO_NULL
, /* doing */
136 ZERO_NULL
, /* proto_getsock */
137 http_getsock_do
, /* doing_getsock */
138 ZERO_NULL
, /* disconnect */
139 PORT_HTTP
, /* defport */
140 PROT_HTTP
, /* protocol */
145 * HTTPS handler interface.
147 const struct Curl_handler Curl_handler_https
= {
148 "HTTPS", /* scheme */
149 ZERO_NULL
, /* setup_connection */
150 Curl_http
, /* do_it */
151 Curl_http_done
, /* done */
152 ZERO_NULL
, /* do_more */
153 Curl_http_connect
, /* connect_it */
154 https_connecting
, /* connecting */
155 ZERO_NULL
, /* doing */
156 https_getsock
, /* proto_getsock */
157 http_getsock_do
, /* doing_getsock */
158 ZERO_NULL
, /* disconnect */
159 PORT_HTTPS
, /* defport */
160 PROT_HTTP
| PROT_HTTPS
| PROT_SSL
/* protocol */
166 * checkheaders() checks the linked list of custom HTTP headers for a
167 * particular header (prefix).
169 * Returns a pointer to the first matching header or NULL if none matched.
171 static char *checkheaders(struct SessionHandle
*data
, const char *thisheader
)
173 struct curl_slist
*head
;
174 size_t thislen
= strlen(thisheader
);
176 for(head
= data
->set
.headers
; head
; head
=head
->next
) {
177 if(strnequal(head
->data
, thisheader
, thislen
))
184 * Strip off leading and trailing whitespace from the value in the
185 * given HTTP header line and return a strdupped copy. Returns NULL in
186 * case of allocation failure. Returns an empty string if the header value
187 * consists entirely of whitespace.
189 char *Curl_copy_header_value(const char *h
)
198 /* Find the end of the header name */
199 while (*h
&& (*h
!= ':'))
203 /* Skip over colon */
206 /* Find the first non-space letter */
208 *start
&& ISSPACE(*start
);
212 /* data is in the host encoding so
213 use '\r' and '\n' instead of 0x0d and 0x0a */
214 end
= strchr(start
, '\r');
216 end
= strchr(start
, '\n');
218 end
= strchr(start
, '\0');
220 /* skip all trailing space letters */
221 for(; ISSPACE(*end
) && (end
> start
); end
--)
224 /* get length of the type */
227 value
= malloc(len
+ 1);
231 memcpy(value
, start
, len
);
232 value
[len
] = 0; /* zero terminate */
238 * http_output_basic() sets up an Authorization: header (or the proxy version)
239 * for HTTP Basic authentication.
243 static CURLcode
http_output_basic(struct connectdata
*conn
, bool proxy
)
246 struct SessionHandle
*data
=conn
->data
;
252 userp
= &conn
->allocptr
.proxyuserpwd
;
253 user
= conn
->proxyuser
;
254 pwd
= conn
->proxypasswd
;
257 userp
= &conn
->allocptr
.userpwd
;
262 snprintf(data
->state
.buffer
, sizeof(data
->state
.buffer
), "%s:%s", user
, pwd
);
263 if(Curl_base64_encode(data
, data
->state
.buffer
,
264 strlen(data
->state
.buffer
),
265 &authorization
) > 0) {
268 *userp
= aprintf( "%sAuthorization: Basic %s\r\n",
273 return CURLE_OUT_OF_MEMORY
;
276 return CURLE_OUT_OF_MEMORY
;
280 /* pickoneauth() selects the most favourable authentication method from the
281 * ones available and the ones we want.
283 * return TRUE if one was picked
285 static bool pickoneauth(struct auth
*pick
)
288 /* only deal with authentication we want */
289 long avail
= pick
->avail
& pick
->want
;
292 /* The order of these checks is highly relevant, as this will be the order
293 of preference in case of the existance of multiple accepted types. */
294 if(avail
& CURLAUTH_GSSNEGOTIATE
)
295 pick
->picked
= CURLAUTH_GSSNEGOTIATE
;
296 else if(avail
& CURLAUTH_DIGEST
)
297 pick
->picked
= CURLAUTH_DIGEST
;
298 else if(avail
& CURLAUTH_NTLM
)
299 pick
->picked
= CURLAUTH_NTLM
;
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 CURLcode
Curl_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 */
341 if(!http
|| !(conn
->protocol
& PROT_HTTP
))
342 /* If this is still NULL, we have not reach very far and we can
343 safely skip this rewinding stuff, or this is attempted to get used
344 when HTTP isn't activated */
347 switch(data
->set
.httpreq
) {
355 bytessent
= http
->writebytecount
;
357 if(conn
->bits
.authneg
)
358 /* This is a state where we are known to be negotiating and we don't send
362 /* figure out how much data we are expected to send */
363 switch(data
->set
.httpreq
) {
365 if(data
->set
.postfieldsize
!= -1)
366 expectsend
= data
->set
.postfieldsize
;
369 if(data
->set
.infilesize
!= -1)
370 expectsend
= data
->set
.infilesize
;
372 case HTTPREQ_POST_FORM
:
373 expectsend
= http
->postsize
;
380 conn
->bits
.rewindaftersend
= FALSE
; /* default */
382 if((expectsend
== -1) || (expectsend
> bytessent
)) {
383 /* There is still data left to send */
384 if((data
->state
.authproxy
.picked
== CURLAUTH_NTLM
) ||
385 (data
->state
.authhost
.picked
== CURLAUTH_NTLM
)) {
386 if(((expectsend
- bytessent
) < 2000) ||
387 (conn
->ntlm
.state
!= NTLMSTATE_NONE
)) {
388 /* The NTLM-negotiation has started *OR* there is just a little (<2K)
389 data left to send, keep on sending. */
391 /* rewind data when completely done sending! */
392 if(!conn
->bits
.authneg
)
393 conn
->bits
.rewindaftersend
= TRUE
;
398 /* this is already marked to get closed */
401 infof(data
, "NTLM send, close instead of sending %" FORMAT_OFF_T
402 " bytes\n", (curl_off_t
)(expectsend
- bytessent
));
405 /* This is not NTLM or NTLM with many bytes left to send: close
407 conn
->bits
.close
= TRUE
;
408 data
->req
.size
= 0; /* don't download any more than 0 bytes */
410 /* There still is data left to send, but this connection is marked for
411 closure so we can safely do the rewind right now */
415 /* we rewind now at once since if we already sent something */
416 return Curl_readrewind(conn
);
422 * Curl_http_auth_act() gets called when a all HTTP headers have been received
423 * and it checks what authentication methods that are available and decides
424 * which one (if any) to use. It will set 'newurl' if an auth metod was
428 CURLcode
Curl_http_auth_act(struct connectdata
*conn
)
430 struct SessionHandle
*data
= conn
->data
;
431 bool pickhost
= FALSE
;
432 bool pickproxy
= FALSE
;
433 CURLcode code
= CURLE_OK
;
435 if(100 <= data
->req
.httpcode
&& 199 >= data
->req
.httpcode
)
436 /* this is a transient response code, ignore */
439 if(data
->state
.authproblem
)
440 return data
->set
.http_fail_on_error
?CURLE_HTTP_RETURNED_ERROR
:CURLE_OK
;
442 if(conn
->bits
.user_passwd
&&
443 ((data
->req
.httpcode
== 401) ||
444 (conn
->bits
.authneg
&& data
->req
.httpcode
< 300))) {
445 pickhost
= pickoneauth(&data
->state
.authhost
);
447 data
->state
.authproblem
= TRUE
;
449 if(conn
->bits
.proxy_user_passwd
&&
450 ((data
->req
.httpcode
== 407) ||
451 (conn
->bits
.authneg
&& data
->req
.httpcode
< 300))) {
452 pickproxy
= pickoneauth(&data
->state
.authproxy
);
454 data
->state
.authproblem
= TRUE
;
457 if(pickhost
|| pickproxy
) {
458 data
->req
.newurl
= strdup(data
->change
.url
); /* clone URL */
459 if(!data
->req
.newurl
)
460 return CURLE_OUT_OF_MEMORY
;
462 if((data
->set
.httpreq
!= HTTPREQ_GET
) &&
463 (data
->set
.httpreq
!= HTTPREQ_HEAD
) &&
464 !conn
->bits
.rewindaftersend
) {
465 code
= Curl_http_perhapsrewind(conn
);
471 else if((data
->req
.httpcode
< 300) &&
472 (!data
->state
.authhost
.done
) &&
473 conn
->bits
.authneg
) {
474 /* no (known) authentication available,
475 authentication is not "done" yet and
476 no authentication seems to be required and
477 we didn't try HEAD or GET */
478 if((data
->set
.httpreq
!= HTTPREQ_GET
) &&
479 (data
->set
.httpreq
!= HTTPREQ_HEAD
)) {
480 data
->req
.newurl
= strdup(data
->change
.url
); /* clone URL */
481 if(!data
->req
.newurl
)
482 return CURLE_OUT_OF_MEMORY
;
483 data
->state
.authhost
.done
= TRUE
;
486 if(Curl_http_should_fail(conn
)) {
487 failf (data
, "The requested URL returned error: %d",
489 code
= CURLE_HTTP_RETURNED_ERROR
;
496 * Curl_http_output_auth() setups the authentication headers for the
497 * host/proxy and the correct authentication
498 * method. conn->data->state.authdone is set to TRUE when authentication is
501 * @param conn all information about the current connection
502 * @param request pointer to the request keyword
503 * @param path pointer to the requested path
504 * @param proxytunnel boolean if this is the request setting up a "proxy
510 http_output_auth(struct connectdata
*conn
,
513 bool proxytunnel
) /* TRUE if this is the request setting
514 up the proxy tunnel */
516 CURLcode result
= CURLE_OK
;
517 struct SessionHandle
*data
= conn
->data
;
518 const char *auth
=NULL
;
519 struct auth
*authhost
;
520 struct auth
*authproxy
;
524 authhost
= &data
->state
.authhost
;
525 authproxy
= &data
->state
.authproxy
;
527 if((conn
->bits
.httpproxy
&& conn
->bits
.proxy_user_passwd
) ||
528 conn
->bits
.user_passwd
)
529 /* continue please */ ;
531 authhost
->done
= TRUE
;
532 authproxy
->done
= TRUE
;
533 return CURLE_OK
; /* no authentication with no user or password */
536 if(authhost
->want
&& !authhost
->picked
)
537 /* The app has selected one or more methods, but none has been picked
538 so far by a server round-trip. Then we set the picked one to the
539 want one, and if this is one single bit it'll be used instantly. */
540 authhost
->picked
= authhost
->want
;
542 if(authproxy
->want
&& !authproxy
->picked
)
543 /* The app has selected one or more methods, but none has been picked so
544 far by a proxy round-trip. Then we set the picked one to the want one,
545 and if this is one single bit it'll be used instantly. */
546 authproxy
->picked
= authproxy
->want
;
548 /* Send proxy authentication header if needed */
549 if(conn
->bits
.httpproxy
&&
550 (conn
->bits
.tunnel_proxy
== proxytunnel
)) {
552 if((authproxy
->picked
== CURLAUTH_GSSNEGOTIATE
) &&
553 data
->state
.negotiate
.context
&&
554 !GSS_ERROR(data
->state
.negotiate
.status
)) {
555 auth
="GSS-Negotiate";
556 result
= Curl_output_negotiate(conn
, TRUE
);
559 authproxy
->done
= TRUE
;
564 if(authproxy
->picked
== CURLAUTH_NTLM
) {
566 result
= Curl_output_ntlm(conn
, TRUE
);
572 if(authproxy
->picked
== CURLAUTH_BASIC
) {
574 if(conn
->bits
.proxy_user_passwd
&&
575 !checkheaders(data
, "Proxy-authorization:")) {
577 result
= http_output_basic(conn
, TRUE
);
581 /* NOTE: http_output_basic() should set 'done' TRUE, as the other auth
582 functions work that way */
583 authproxy
->done
= TRUE
;
585 #ifndef CURL_DISABLE_CRYPTO_AUTH
586 else if(authproxy
->picked
== CURLAUTH_DIGEST
) {
588 result
= Curl_output_digest(conn
,
590 (const unsigned char *)request
,
591 (const unsigned char *)path
);
597 infof(data
, "Proxy auth using %s with user '%s'\n",
598 auth
, conn
->proxyuser
?conn
->proxyuser
:"");
599 authproxy
->multi
= (bool)(!authproxy
->done
);
602 authproxy
->multi
= FALSE
;
605 /* we have no proxy so let's pretend we're done authenticating
607 authproxy
->done
= TRUE
;
609 /* To prevent the user+password to get sent to other than the original
610 host due to a location-follow, we do some weirdo checks here */
611 if(!data
->state
.this_is_a_follow
||
613 !data
->state
.first_host
||
614 curl_strequal(data
->state
.first_host
, conn
->host
.name
) ||
615 data
->set
.http_disable_hostname_check_before_authentication
) {
617 /* Send web authentication header if needed */
621 if((authhost
->picked
== CURLAUTH_GSSNEGOTIATE
) &&
622 data
->state
.negotiate
.context
&&
623 !GSS_ERROR(data
->state
.negotiate
.status
)) {
624 auth
="GSS-Negotiate";
625 result
= Curl_output_negotiate(conn
, FALSE
);
628 authhost
->done
= TRUE
;
633 if(authhost
->picked
== CURLAUTH_NTLM
) {
635 result
= Curl_output_ntlm(conn
, FALSE
);
642 #ifndef CURL_DISABLE_CRYPTO_AUTH
643 if(authhost
->picked
== CURLAUTH_DIGEST
) {
645 result
= Curl_output_digest(conn
,
646 FALSE
, /* not a proxy */
647 (const unsigned char *)request
,
648 (const unsigned char *)path
);
653 if(authhost
->picked
== CURLAUTH_BASIC
) {
654 if(conn
->bits
.user_passwd
&&
655 !checkheaders(data
, "Authorization:")) {
657 result
= http_output_basic(conn
, FALSE
);
661 /* basic is always ready */
662 authhost
->done
= TRUE
;
666 infof(data
, "Server auth using %s with user '%s'\n",
669 authhost
->multi
= (bool)(!authhost
->done
);
672 authhost
->multi
= FALSE
;
676 authhost
->done
= TRUE
;
683 * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
684 * headers. They are dealt with both in the transfer.c main loop and in the
685 * proxy CONNECT loop.
688 CURLcode
Curl_http_input_auth(struct connectdata
*conn
,
690 const char *header
) /* the first non-space */
693 * This resource requires authentication
695 struct SessionHandle
*data
= conn
->data
;
701 if(httpcode
== 407) {
702 start
= header
+strlen("Proxy-authenticate:");
703 availp
= &data
->info
.proxyauthavail
;
704 authp
= &data
->state
.authproxy
;
707 start
= header
+strlen("WWW-Authenticate:");
708 availp
= &data
->info
.httpauthavail
;
709 authp
= &data
->state
.authhost
;
712 /* pass all white spaces */
713 while(*start
&& ISSPACE(*start
))
717 * Here we check if we want the specific single authentication (using ==) and
718 * if we do, we initiate usage of it.
720 * If the provided authentication is wanted as one out of several accepted
721 * types (using &), we OR this authentication type to the authavail
726 if(checkprefix("GSS-Negotiate", start
) ||
727 checkprefix("Negotiate", start
)) {
728 *availp
|= CURLAUTH_GSSNEGOTIATE
;
729 authp
->avail
|= CURLAUTH_GSSNEGOTIATE
;
730 if(authp
->picked
== CURLAUTH_GSSNEGOTIATE
) {
731 /* if exactly this is wanted, go */
732 int neg
= Curl_input_negotiate(conn
, (bool)(httpcode
== 407), start
);
734 DEBUGASSERT(!data
->req
.newurl
);
735 data
->req
.newurl
= strdup(data
->change
.url
);
736 data
->state
.authproblem
= (data
->req
.newurl
== NULL
);
739 infof(data
, "Authentication problem. Ignoring this.\n");
740 data
->state
.authproblem
= TRUE
;
747 /* NTLM support requires the SSL crypto libs */
748 if(checkprefix("NTLM", start
)) {
749 *availp
|= CURLAUTH_NTLM
;
750 authp
->avail
|= CURLAUTH_NTLM
;
751 if(authp
->picked
== CURLAUTH_NTLM
) {
752 /* NTLM authentication is picked and activated */
754 Curl_input_ntlm(conn
, (bool)(httpcode
== 407), start
);
756 if(CURLNTLM_BAD
!= ntlm
)
757 data
->state
.authproblem
= FALSE
;
759 infof(data
, "Authentication problem. Ignoring this.\n");
760 data
->state
.authproblem
= TRUE
;
766 #ifndef CURL_DISABLE_CRYPTO_AUTH
767 if(checkprefix("Digest", start
)) {
768 if((authp
->avail
& CURLAUTH_DIGEST
) != 0) {
769 infof(data
, "Ignoring duplicate digest auth header.\n");
773 *availp
|= CURLAUTH_DIGEST
;
774 authp
->avail
|= CURLAUTH_DIGEST
;
776 /* We call this function on input Digest headers even if Digest
777 * authentication isn't activated yet, as we need to store the
778 * incoming data from this header in case we are gonna use Digest. */
779 dig
= Curl_input_digest(conn
, (bool)(httpcode
== 407), start
);
781 if(CURLDIGEST_FINE
!= dig
) {
782 infof(data
, "Authentication problem. Ignoring this.\n");
783 data
->state
.authproblem
= TRUE
;
789 if(checkprefix("Basic", start
)) {
790 *availp
|= CURLAUTH_BASIC
;
791 authp
->avail
|= CURLAUTH_BASIC
;
792 if(authp
->picked
== CURLAUTH_BASIC
) {
793 /* We asked for Basic authentication but got a 40X back
794 anyway, which basicly means our name+password isn't
796 authp
->avail
= CURLAUTH_NONE
;
797 infof(data
, "Authentication problem. Ignoring this.\n");
798 data
->state
.authproblem
= TRUE
;
806 * Curl_http_should_fail() determines whether an HTTP response has gotten us
807 * into an error state or not.
809 * @param conn all information about the current connection
811 * @retval 0 communications should continue
813 * @retval 1 communications should not continue
815 int Curl_http_should_fail(struct connectdata
*conn
)
817 struct SessionHandle
*data
;
824 httpcode
= data
->req
.httpcode
;
827 ** If we haven't been asked to fail on error,
830 if(!data
->set
.http_fail_on_error
)
834 ** Any code < 400 is never terminal.
839 if(data
->state
.resume_from
&&
840 (data
->set
.httpreq
==HTTPREQ_GET
) &&
842 /* "Requested Range Not Satisfiable", just proceed and
843 pretend this is no error */
848 ** Any code >= 400 that's not 401 or 407 is always
851 if((httpcode
!= 401) &&
856 ** All we have left to deal with is 401 and 407
858 DEBUGASSERT((httpcode
== 401) || (httpcode
== 407));
861 ** Examine the current authentication state to see if this
862 ** is an error. The idea is for this function to get
863 ** called after processing all the headers in a response
864 ** message. So, if we've been to asked to authenticate a
865 ** particular stage, and we've done it, we're OK. But, if
866 ** we're already completely authenticated, it's not OK to
867 ** get another 401 or 407.
869 ** It is possible for authentication to go stale such that
870 ** the client needs to reauthenticate. Once that info is
871 ** available, use it here.
873 #if 0 /* set to 1 when debugging this functionality */
874 infof(data
,"%s: authstage = %d\n",__FUNCTION__
,data
->state
.authstage
);
875 infof(data
,"%s: authwant = 0x%08x\n",__FUNCTION__
,data
->state
.authwant
);
876 infof(data
,"%s: authavail = 0x%08x\n",__FUNCTION__
,data
->state
.authavail
);
877 infof(data
,"%s: httpcode = %d\n",__FUNCTION__
,k
->httpcode
);
878 infof(data
,"%s: authdone = %d\n",__FUNCTION__
,data
->state
.authdone
);
879 infof(data
,"%s: newurl = %s\n",__FUNCTION__
,data
->req
.newurl
?
880 data
->req
.newurl
: "(null)");
881 infof(data
,"%s: authproblem = %d\n",__FUNCTION__
,data
->state
.authproblem
);
885 ** Either we're not authenticating, or we're supposed to
886 ** be authenticating something else. This is an error.
888 if((httpcode
== 401) && !conn
->bits
.user_passwd
)
890 if((httpcode
== 407) && !conn
->bits
.proxy_user_passwd
)
893 return data
->state
.authproblem
;
897 * readmoredata() is a "fread() emulation" to provide POST and/or request
898 * data. It is used when a huge POST is to be made and the entire chunk wasn't
899 * sent in the first send(). This function will then be called from the
900 * transfer.c loop when more data is to be sent to the peer.
902 * Returns the amount of bytes it filled the buffer with.
904 static size_t readmoredata(char *buffer
,
909 struct connectdata
*conn
= (struct connectdata
*)userp
;
910 struct HTTP
*http
= conn
->data
->state
.proto
.http
;
911 size_t fullsize
= size
* nitems
;
913 if(0 == http
->postsize
)
914 /* nothing to return */
917 /* make sure that a HTTP request is never sent away chunked! */
918 conn
->data
->req
.forbidchunk
= (bool)(http
->sending
== HTTPSEND_REQUEST
);
920 if(http
->postsize
<= (curl_off_t
)fullsize
) {
921 memcpy(buffer
, http
->postdata
, (size_t)http
->postsize
);
922 fullsize
= (size_t)http
->postsize
;
924 if(http
->backup
.postsize
) {
925 /* move backup data into focus and continue on that */
926 http
->postdata
= http
->backup
.postdata
;
927 http
->postsize
= http
->backup
.postsize
;
928 conn
->fread_func
= http
->backup
.fread_func
;
929 conn
->fread_in
= http
->backup
.fread_in
;
931 http
->sending
++; /* move one step up */
933 http
->backup
.postsize
=0;
941 memcpy(buffer
, http
->postdata
, fullsize
);
942 http
->postdata
+= fullsize
;
943 http
->postsize
-= fullsize
;
948 /* ------------------------------------------------------------------------- */
950 * The add_buffer series of functions are used to build one large memory chunk
951 * from repeated function invokes. Used so that the entire HTTP request can
960 typedef struct send_buffer send_buffer
;
962 static CURLcode
add_custom_headers(struct connectdata
*conn
,
963 send_buffer
*req_buffer
);
965 add_buffer(send_buffer
*in
, const void *inptr
, size_t size
);
968 * add_buffer_init() sets up and returns a fine buffer struct
971 send_buffer
*add_buffer_init(void)
974 blonk
=(send_buffer
*)malloc(sizeof(send_buffer
));
976 memset(blonk
, 0, sizeof(send_buffer
));
979 return NULL
; /* failed, go home */
983 * add_buffer_send() sends a header buffer and frees all associated memory.
984 * Body data may be appended to the header data if desired.
989 CURLcode
add_buffer_send(send_buffer
*in
,
990 struct connectdata
*conn
,
991 long *bytes_written
, /* add the number of sent bytes
993 size_t included_body_bytes
, /* how much of the buffer
994 contains body data */
1002 struct HTTP
*http
= conn
->data
->state
.proto
.http
;
1004 curl_socket_t sockfd
;
1007 DEBUGASSERT(socketindex
<= SECONDARYSOCKET
);
1009 sockfd
= conn
->sock
[socketindex
];
1011 /* The looping below is required since we use non-blocking sockets, but due
1012 to the circumstances we will just loop and try again and again etc */
1015 size
= in
->size_used
;
1017 headersize
= size
- included_body_bytes
; /* the initial part that isn't body
1020 DEBUGASSERT(size
> included_body_bytes
);
1022 #ifdef CURL_DOES_CONVERSIONS
1023 res
= Curl_convert_to_network(conn
->data
, ptr
, headersize
);
1024 /* Curl_convert_to_network calls failf if unsuccessful */
1025 if(res
!= CURLE_OK
) {
1026 /* conversion failed, free memory and return to the caller */
1032 #endif /* CURL_DOES_CONVERSIONS */
1034 if(conn
->protocol
& PROT_HTTPS
) {
1035 /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
1036 when we speak HTTPS, as if only a fraction of it is sent now, this data
1037 needs to fit into the normal read-callback buffer later on and that
1038 buffer is using this size.
1041 sendsize
= (size
> CURL_MAX_WRITE_SIZE
)?CURL_MAX_WRITE_SIZE
:size
;
1043 /* OpenSSL is very picky and we must send the SAME buffer pointer to the
1044 library when we attempt to re-send this buffer. Sending the same data
1045 is not enough, we must use the exact same address. For this reason, we
1046 must copy the data to the uploadbuffer first, since that is the buffer
1047 we will be using if this send is retried later.
1049 memcpy(conn
->data
->state
.uploadbuffer
, ptr
, sendsize
);
1050 ptr
= conn
->data
->state
.uploadbuffer
;
1055 res
= Curl_write(conn
, sockfd
, ptr
, sendsize
, &amount
);
1057 if(CURLE_OK
== res
) {
1059 * Note that we may not send the entire chunk at once, and we have a set
1060 * number of data bytes at the end of the big buffer (out of which we may
1061 * only send away a part).
1063 /* how much of the header that was sent */
1064 size_t headlen
= (size_t)amount
>headersize
?headersize
:(size_t)amount
;
1065 size_t bodylen
= amount
- headlen
;
1067 if(conn
->data
->set
.verbose
) {
1068 /* this data _may_ contain binary stuff */
1069 Curl_debug(conn
->data
, CURLINFO_HEADER_OUT
, ptr
, headlen
, conn
);
1070 if((size_t)amount
> headlen
) {
1071 /* there was body data sent beyond the initial header part, pass that
1072 on to the debug callback too */
1073 Curl_debug(conn
->data
, CURLINFO_DATA_OUT
,
1074 ptr
+headlen
, bodylen
, conn
);
1078 /* since we sent a piece of the body here, up the byte counter for it
1080 http
->writebytecount
+= bodylen
;
1082 *bytes_written
+= amount
;
1085 if((size_t)amount
!= size
) {
1086 /* The whole request could not be sent in one system call. We must
1087 queue it up and send it later when we get the chance. We must not
1088 loop here and wait until it might work again. */
1092 ptr
= in
->buffer
+ amount
;
1094 /* backup the currently set pointers */
1095 http
->backup
.fread_func
= conn
->fread_func
;
1096 http
->backup
.fread_in
= conn
->fread_in
;
1097 http
->backup
.postdata
= http
->postdata
;
1098 http
->backup
.postsize
= http
->postsize
;
1100 /* set the new pointers for the request-sending */
1101 conn
->fread_func
= (curl_read_callback
)readmoredata
;
1102 conn
->fread_in
= (void *)conn
;
1103 http
->postdata
= ptr
;
1104 http
->postsize
= (curl_off_t
)size
;
1106 http
->send_buffer
= in
;
1107 http
->sending
= HTTPSEND_REQUEST
;
1111 http
->sending
= HTTPSEND_BODY
;
1112 /* the full buffer was sent, clean up and return */
1115 if((size_t)amount
!= size
)
1116 /* We have no continue-send mechanism now, fail. This can only happen
1117 when this function is used from the CONNECT sending function. We
1118 currently (stupidly) assume that the whole request is always sent
1119 away in the first single chunk.
1123 return CURLE_SEND_ERROR
;
1125 conn
->writechannel_inuse
= FALSE
;
1137 * add_bufferf() add the formatted input to the buffer.
1140 CURLcode
add_bufferf(send_buffer
*in
, const char *fmt
, ...)
1145 s
= vaprintf(fmt
, ap
); /* this allocs a new string to append */
1149 CURLcode result
= add_buffer(in
, s
, strlen(s
));
1153 /* If we failed, we cleanup the whole buffer and return error */
1157 return CURLE_OUT_OF_MEMORY
;
1161 * add_buffer() appends a memory chunk to the existing buffer
1164 CURLcode
add_buffer(send_buffer
*in
, const void *inptr
, size_t size
)
1169 if(~size
< in
->size_used
) {
1170 /* If resulting used size of send buffer would wrap size_t, cleanup
1171 the whole buffer and return error. Otherwise the required buffer
1172 size will fit into a single allocatable memory chunk */
1173 Curl_safefree(in
->buffer
);
1175 return CURLE_OUT_OF_MEMORY
;
1179 ((in
->size_used
+ size
) > (in
->size_max
- 1))) {
1181 /* If current buffer size isn't enough to hold the result, use a
1182 buffer size that doubles the required size. If this new size
1183 would wrap size_t, then just use the largest possible one */
1185 if((size
> (size_t)-1/2) || (in
->size_used
> (size_t)-1/2) ||
1186 (~(size
*2) < (in
->size_used
*2)))
1187 new_size
= (size_t)-1;
1189 new_size
= (in
->size_used
+size
)*2;
1192 /* we have a buffer, enlarge the existing one */
1193 new_rb
= (char *)realloc(in
->buffer
, new_size
);
1195 /* create a new buffer */
1196 new_rb
= (char *)malloc(new_size
);
1199 /* If we failed, we cleanup the whole buffer and return error */
1200 Curl_safefree(in
->buffer
);
1202 return CURLE_OUT_OF_MEMORY
;
1205 in
->buffer
= new_rb
;
1206 in
->size_max
= new_size
;
1208 memcpy(&in
->buffer
[in
->size_used
], inptr
, size
);
1210 in
->size_used
+= size
;
1215 /* end of the add_buffer functions */
1216 /* ------------------------------------------------------------------------- */
1219 * Curl_compareheader()
1221 * Returns TRUE if 'headerline' contains the 'header' with given 'content'.
1222 * Pass headers WITH the colon.
1225 Curl_compareheader(const char *headerline
, /* line to check */
1226 const char *header
, /* header keyword _with_ colon */
1227 const char *content
) /* content string to find */
1229 /* RFC2616, section 4.2 says: "Each header field consists of a name followed
1230 * by a colon (":") and the field value. Field names are case-insensitive.
1231 * The field value MAY be preceded by any amount of LWS, though a single SP
1234 size_t hlen
= strlen(header
);
1240 if(!strnequal(headerline
, header
, hlen
))
1241 return FALSE
; /* doesn't start with header */
1243 /* pass the header */
1244 start
= &headerline
[hlen
];
1246 /* pass all white spaces */
1247 while(*start
&& ISSPACE(*start
))
1250 /* find the end of the header line */
1251 end
= strchr(start
, '\r'); /* lines end with CRLF */
1253 /* in case there's a non-standard compliant line here */
1254 end
= strchr(start
, '\n');
1257 /* hm, there's no line ending here, use the zero byte! */
1258 end
= strchr(start
, '\0');
1261 len
= end
-start
; /* length of the content part of the input line */
1262 clen
= strlen(content
); /* length of the word to find */
1264 /* find the content string in the rest of the line */
1265 for(;len
>=clen
;len
--, start
++) {
1266 if(strnequal(start
, content
, clen
))
1267 return TRUE
; /* match! */
1270 return FALSE
; /* no match */
1274 * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
1275 * function will issue the necessary commands to get a seamless tunnel through
1276 * this proxy. After that, the socket can be used just as a normal socket.
1278 * This badly needs to be rewritten. CONNECT should be sent and dealt with
1279 * like any ordinary HTTP request, and not specially crafted like this. This
1280 * function only remains here like this for now since the rewrite is a bit too
1281 * much work to do at the moment.
1283 * This function is BLOCKING which is nasty for all multi interface using apps.
1286 CURLcode
Curl_proxyCONNECT(struct connectdata
*conn
,
1288 const char *hostname
,
1289 unsigned short remote_port
)
1292 struct SessionHandle
*data
=conn
->data
;
1293 struct SingleRequest
*k
= &data
->req
;
1297 data
->set
.timeout
?data
->set
.timeout
:PROXY_TIMEOUT
; /* in milliseconds */
1298 curl_socket_t tunnelsocket
= conn
->sock
[sockindex
];
1300 bool closeConnection
= FALSE
;
1301 bool chunked_encoding
= FALSE
;
1305 #define SELECT_ERROR 1
1306 #define SELECT_TIMEOUT 2
1307 int error
= SELECT_OK
;
1309 conn
->bits
.proxy_connect_closed
= FALSE
;
1312 if(!conn
->bits
.tunnel_connecting
) { /* BEGIN CONNECT PHASE */
1314 send_buffer
*req_buffer
;
1316 infof(data
, "Establish HTTP proxy tunnel to %s:%d\n",
1317 hostname
, remote_port
);
1319 if(data
->req
.newurl
) {
1320 /* This only happens if we've looped here due to authentication
1321 reasons, and we don't really use the newly cloned URL here
1322 then. Just free() it. */
1323 free(data
->req
.newurl
);
1324 data
->req
.newurl
= NULL
;
1327 /* initialize a dynamic send-buffer */
1328 req_buffer
= add_buffer_init();
1331 return CURLE_OUT_OF_MEMORY
;
1333 host_port
= aprintf("%s:%d", hostname
, remote_port
);
1336 return CURLE_OUT_OF_MEMORY
;
1339 /* Setup the proxy-authorization header, if any */
1340 result
= http_output_auth(conn
, (char *)"CONNECT", host_port
, TRUE
);
1342 if(CURLE_OK
== result
) {
1343 char *host
=(char *)"";
1344 const char *proxyconn
="";
1345 const char *useragent
="";
1347 if(!checkheaders(data
, "Host:")) {
1348 host
= aprintf("Host: %s\r\n", host_port
);
1352 return CURLE_OUT_OF_MEMORY
;
1355 if(!checkheaders(data
, "Proxy-Connection:"))
1356 proxyconn
= "Proxy-Connection: Keep-Alive\r\n";
1358 if(!checkheaders(data
, "User-Agent:") &&
1359 data
->set
.str
[STRING_USERAGENT
])
1360 useragent
= conn
->allocptr
.uagent
;
1362 /* Send the connect request to the proxy */
1365 add_bufferf(req_buffer
,
1366 "CONNECT %s:%d HTTP/1.0\r\n"
1368 "%s" /* Proxy-Authorization */
1369 "%s" /* User-Agent */
1370 "%s", /* Proxy-Connection */
1371 hostname
, remote_port
,
1373 conn
->allocptr
.proxyuserpwd
?
1374 conn
->allocptr
.proxyuserpwd
:"",
1381 if(CURLE_OK
== result
)
1382 result
= add_custom_headers(conn
, req_buffer
);
1384 if(CURLE_OK
== result
)
1385 /* CRLF terminate the request */
1386 result
= add_bufferf(req_buffer
, "\r\n");
1388 if(CURLE_OK
== result
) {
1389 /* Now send off the request */
1390 result
= add_buffer_send(req_buffer
, conn
,
1391 &data
->info
.request_size
, 0, sockindex
);
1395 failf(data
, "Failed sending CONNECT to proxy");
1398 Curl_safefree(req_buffer
);
1402 conn
->bits
.tunnel_connecting
= TRUE
;
1403 } /* END CONNECT PHASE */
1405 /* now we've issued the CONNECT and we're waiting to hear back -
1406 we try not to block here in multi-mode because that might be a LONG
1407 wait if the proxy cannot connect-through to the remote host. */
1409 /* if timeout is requested, find out how much remaining time we have */
1410 check
= timeout
- /* timeout time */
1411 Curl_tvdiff(Curl_tvnow(), conn
->now
); /* spent time */
1413 failf(data
, "Proxy CONNECT aborted due to timeout");
1414 error
= SELECT_TIMEOUT
; /* already too little time */
1418 /* if we're in multi-mode and we would block, return instead for a retry */
1419 if(Curl_if_multi
== data
->state
.used_interface
) {
1420 if(0 == Curl_socket_ready(tunnelsocket
, CURL_SOCKET_BAD
, 0))
1421 /* return so we'll be called again polling-style */
1425 "Multi mode finished polling for response from "
1430 DEBUGF(infof(data
, "Easy mode waiting for response from proxy CONNECT."));
1433 /* at this point, either:
1434 1) we're in easy-mode and so it's okay to block waiting for a CONNECT
1436 2) we're in multi-mode and we didn't block - it's either an error or we
1437 now have some data waiting.
1438 In any case, the tunnel_connecting phase is over. */
1439 conn
->bits
.tunnel_connecting
= FALSE
;
1441 { /* BEGIN NEGOTIATION PHASE */
1442 size_t nread
; /* total size read */
1443 int perline
; /* count bytes per line */
1449 ptr
=data
->state
.buffer
;
1456 while((nread
<BUFSIZE
) && (keepon
&& !error
)) {
1458 /* if timeout is requested, find out how much remaining time we have */
1459 check
= timeout
- /* timeout time */
1460 Curl_tvdiff(Curl_tvnow(), conn
->now
); /* spent time */
1462 failf(data
, "Proxy CONNECT aborted due to timeout");
1463 error
= SELECT_TIMEOUT
; /* already too little time */
1467 /* loop every second at least, less if the timeout is near */
1468 switch (Curl_socket_ready(tunnelsocket
, CURL_SOCKET_BAD
,
1469 check
<1000L?(int)check
:1000)) {
1470 case -1: /* select() error, stop reading */
1471 error
= SELECT_ERROR
;
1472 failf(data
, "Proxy CONNECT aborted due to select/poll error");
1474 case 0: /* timeout */
1477 DEBUGASSERT(ptr
+BUFSIZE
-nread
<= data
->state
.buffer
+BUFSIZE
+1);
1478 res
= Curl_read(conn
, tunnelsocket
, ptr
, BUFSIZE
-nread
, &gotbytes
);
1481 continue; /* go loop yourself */
1484 else if(gotbytes
<= 0) {
1486 if(data
->set
.proxyauth
&& data
->state
.authproxy
.avail
) {
1487 /* proxy auth was requested and there was proxy auth available,
1488 then deem this as "mere" proxy disconnect */
1489 conn
->bits
.proxy_connect_closed
= TRUE
;
1492 error
= SELECT_ERROR
;
1493 failf(data
, "Proxy CONNECT aborted");
1498 * We got a whole chunk of data, which can be anything from one
1499 * byte to a set of lines and possibly just a piece of the last
1507 /* This means we are currently ignoring a response-body */
1509 nread
= 0; /* make next read start over in the read buffer */
1510 ptr
=data
->state
.buffer
;
1512 /* A Content-Length based body: simply count down the counter
1513 and make sure to break out of the loop when we're done! */
1521 /* chunked-encoded body, so we need to do the chunked dance
1522 properly to know when the end of the body is reached */
1524 ssize_t tookcareof
=0;
1526 /* now parse the chunked piece of data so that we can
1527 properly tell when the stream ends */
1528 r
= Curl_httpchunk_read(conn
, ptr
, gotbytes
, &tookcareof
);
1529 if(r
== CHUNKE_STOP
) {
1530 /* we're done reading chunks! */
1531 infof(data
, "chunk reading DONE\n");
1535 infof(data
, "Read %d bytes of chunk, continue\n",
1540 for(i
= 0; i
< gotbytes
; ptr
++, i
++) {
1541 perline
++; /* amount of bytes in this line so far */
1546 /* output debug if that is requested */
1547 if(data
->set
.verbose
)
1548 Curl_debug(data
, CURLINFO_HEADER_IN
,
1549 line_start
, (size_t)perline
, conn
);
1551 /* send the header to the callback */
1552 writetype
= CLIENTWRITE_HEADER
;
1553 if(data
->set
.include_header
)
1554 writetype
|= CLIENTWRITE_BODY
;
1556 result
= Curl_client_write(conn
, writetype
, line_start
,
1561 /* Newlines are CRLF, so the CR is ignored as the line isn't
1562 really terminated until the LF comes. Treat a following CR
1563 as end-of-headers as well.*/
1565 if(('\r' == line_start
[0]) ||
1566 ('\n' == line_start
[0])) {
1567 /* end of response-headers from the proxy */
1568 nread
= 0; /* make next read start over in the read
1570 ptr
=data
->state
.buffer
;
1571 if((407 == k
->httpcode
) && !data
->state
.authproblem
) {
1572 /* If we get a 407 response code with content length
1573 when we have no auth problem, we must ignore the
1574 whole response-body */
1579 infof(data
, "Ignore %" FORMAT_OFF_T
1580 " bytes of response-body\n", cl
);
1581 /* remove the remaining chunk of what we already
1583 cl
-= (gotbytes
- i
);
1586 /* if the whole thing was already read, we are done!
1590 else if(chunked_encoding
) {
1592 /* We set ignorebody true here since the chunked
1593 decoder function will acknowledge that. Pay
1594 attention so that this is cleared again when this
1595 function returns! */
1596 k
->ignorebody
= TRUE
;
1597 infof(data
, "%d bytes of chunk left\n", gotbytes
-i
);
1599 if(line_start
[1] == '\n') {
1600 /* this can only be a LF if the letter at index 0
1606 /* now parse the chunked piece of data so that we can
1607 properly tell when the stream ends */
1608 r
= Curl_httpchunk_read(conn
, line_start
+1,
1609 gotbytes
-i
, &gotbytes
);
1610 if(r
== CHUNKE_STOP
) {
1611 /* we're done reading chunks! */
1612 infof(data
, "chunk reading DONE\n");
1616 infof(data
, "Read %d bytes of chunk, continue\n",
1620 /* without content-length or chunked encoding, we
1621 can't keep the connection alive since the close is
1622 the end signal so we bail out at once instead */
1628 break; /* breaks out of for-loop, not switch() */
1631 /* keep a backup of the position we are about to blank */
1632 letter
= line_start
[perline
];
1633 line_start
[perline
]=0; /* zero terminate the buffer */
1634 if((checkprefix("WWW-Authenticate:", line_start
) &&
1635 (401 == k
->httpcode
)) ||
1636 (checkprefix("Proxy-authenticate:", line_start
) &&
1637 (407 == k
->httpcode
))) {
1638 result
= Curl_http_input_auth(conn
, k
->httpcode
,
1643 else if(checkprefix("Content-Length:", line_start
)) {
1644 cl
= curlx_strtoofft(line_start
+ strlen("Content-Length:"),
1647 else if(Curl_compareheader(line_start
,
1648 "Connection:", "close"))
1649 closeConnection
= TRUE
;
1650 else if(Curl_compareheader(line_start
,
1651 "Transfer-Encoding:", "chunked")) {
1652 infof(data
, "CONNECT responded chunked\n");
1653 chunked_encoding
= TRUE
;
1654 /* init our chunky engine */
1655 Curl_httpchunk_init(conn
);
1657 else if(Curl_compareheader(line_start
,
1658 "Proxy-Connection:", "close"))
1659 closeConnection
= TRUE
;
1660 else if(2 == sscanf(line_start
, "HTTP/1.%d %d",
1663 /* store the HTTP code from the proxy */
1664 data
->info
.httpproxycode
= k
->httpcode
;
1666 /* put back the letter we blanked out before */
1667 line_start
[perline
]= letter
;
1669 perline
=0; /* line starts over here */
1670 line_start
= ptr
+1; /* this skips the zero byte we wrote */
1676 if(Curl_pgrsUpdate(conn
))
1677 return CURLE_ABORTED_BY_CALLBACK
;
1678 } /* while there's buffer left and loop is requested */
1681 return CURLE_RECV_ERROR
;
1683 if(data
->info
.httpproxycode
!= 200) {
1684 /* Deal with the possibly already received authenticate
1685 headers. 'newurl' is set to a new URL if we must loop. */
1686 result
= Curl_http_auth_act(conn
);
1690 if(conn
->bits
.close
)
1691 /* the connection has been marked for closure, most likely in the
1692 Curl_http_auth_act() function and thus we can kill it at once
1695 closeConnection
= TRUE
;
1698 if(closeConnection
&& data
->req
.newurl
) {
1699 /* Connection closed by server. Don't use it anymore */
1700 sclose(conn
->sock
[sockindex
]);
1701 conn
->sock
[sockindex
] = CURL_SOCKET_BAD
;
1704 } /* END NEGOTIATION PHASE */
1705 } while(data
->req
.newurl
);
1707 if(200 != data
->req
.httpcode
) {
1708 failf(data
, "Received HTTP code %d from proxy after CONNECT",
1709 data
->req
.httpcode
);
1711 if(closeConnection
&& data
->req
.newurl
)
1712 conn
->bits
.proxy_connect_closed
= TRUE
;
1714 return CURLE_RECV_ERROR
;
1717 /* If a proxy-authorization header was used for the proxy, then we should
1718 make sure that it isn't accidentally used for the document request
1719 after we've connected. So let's free and clear it here. */
1720 Curl_safefree(conn
->allocptr
.proxyuserpwd
);
1721 conn
->allocptr
.proxyuserpwd
= NULL
;
1723 data
->state
.authproxy
.done
= TRUE
;
1725 infof (data
, "Proxy replied OK to CONNECT request\n");
1726 data
->req
.ignorebody
= FALSE
; /* put it (back) to non-ignore state */
1731 * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
1732 * the generic Curl_connect().
1734 CURLcode
Curl_http_connect(struct connectdata
*conn
, bool *done
)
1736 struct SessionHandle
*data
;
1741 /* We default to persistent connections. We set this already in this connect
1742 function to make the re-use checks properly be able to check this bit. */
1743 conn
->bits
.close
= FALSE
;
1745 /* If we are not using a proxy and we want a secure connection, perform SSL
1746 * initialization & connection now. If using a proxy with https, then we
1747 * must tell the proxy to CONNECT to the host we want to talk to. Only
1748 * after the connect has occurred, can we start talking SSL
1751 if(conn
->bits
.tunnel_proxy
&& conn
->bits
.httpproxy
) {
1753 /* either SSL over proxy, or explicitly asked for */
1754 result
= Curl_proxyCONNECT(conn
, FIRSTSOCKET
,
1757 if(CURLE_OK
!= result
)
1761 if(conn
->bits
.tunnel_connecting
) {
1762 /* nothing else to do except wait right now - we're not done here. */
1766 if(!data
->state
.this_is_a_follow
) {
1767 /* this is not a followed location, get the original host name */
1768 if(data
->state
.first_host
)
1769 /* Free to avoid leaking memory on multiple requests*/
1770 free(data
->state
.first_host
);
1772 data
->state
.first_host
= strdup(conn
->host
.name
);
1773 if(!data
->state
.first_host
)
1774 return CURLE_OUT_OF_MEMORY
;
1777 if(conn
->protocol
& PROT_HTTPS
) {
1778 /* perform SSL initialization */
1779 if(data
->state
.used_interface
== Curl_if_multi
) {
1780 result
= https_connecting(conn
, done
);
1786 result
= Curl_ssl_connect(conn
, FIRSTSOCKET
);
1799 /* this returns the socket to wait for in the DO and DOING state for the multi
1800 interface and then we're always _sending_ a request and thus we wait for
1801 the single socket to become writable only */
1802 static int http_getsock_do(struct connectdata
*conn
,
1803 curl_socket_t
*socks
,
1807 (void)numsocks
; /* unused, we trust it to be at least 1 */
1808 socks
[0] = conn
->sock
[FIRSTSOCKET
];
1809 return GETSOCK_WRITESOCK(0);
1812 static CURLcode
https_connecting(struct connectdata
*conn
, bool *done
)
1815 DEBUGASSERT((conn
) && (conn
->protocol
& PROT_HTTPS
));
1817 /* perform SSL initialization for this socket */
1818 result
= Curl_ssl_connect_nonblocking(conn
, FIRSTSOCKET
, done
);
1820 conn
->bits
.close
= TRUE
; /* a failed connection is marked for closure
1821 to prevent (bad) re-use or similar */
1829 /* This function is OpenSSL-specific. It should be made to query the generic
1830 SSL layer instead. */
1831 static int https_getsock(struct connectdata
*conn
,
1832 curl_socket_t
*socks
,
1835 if(conn
->protocol
& PROT_HTTPS
) {
1836 struct ssl_connect_data
*connssl
= &conn
->ssl
[FIRSTSOCKET
];
1839 return GETSOCK_BLANK
;
1841 if(connssl
->connecting_state
== ssl_connect_2_writing
) {
1843 socks
[0] = conn
->sock
[FIRSTSOCKET
];
1844 return GETSOCK_WRITESOCK(0);
1846 else if(connssl
->connecting_state
== ssl_connect_2_reading
) {
1848 socks
[0] = conn
->sock
[FIRSTSOCKET
];
1849 return GETSOCK_READSOCK(0);
1856 static int https_getsock(struct connectdata
*conn
,
1857 curl_socket_t
*socks
,
1863 return GETSOCK_BLANK
;
1867 static int https_getsock(struct connectdata
*conn
,
1868 curl_socket_t
*socks
,
1874 return GETSOCK_BLANK
;
1878 static int https_getsock(struct connectdata
*conn
,
1879 curl_socket_t
*socks
,
1885 return GETSOCK_BLANK
;
1893 * Curl_http_done() gets called from Curl_done() after a single HTTP request
1894 * has been performed.
1897 CURLcode
Curl_http_done(struct connectdata
*conn
,
1898 CURLcode status
, bool premature
)
1900 struct SessionHandle
*data
= conn
->data
;
1901 struct HTTP
*http
=data
->state
.proto
.http
;
1902 (void)premature
; /* not used */
1904 /* set the proper values (possibly modified on POST) */
1905 conn
->fread_func
= data
->set
.fread_func
; /* restore */
1906 conn
->fread_in
= data
->set
.in
; /* restore */
1907 conn
->seek_func
= data
->set
.seek_func
; /* restore */
1908 conn
->seek_client
= data
->set
.seek_client
; /* restore */
1913 if(http
->send_buffer
) {
1914 send_buffer
*buff
= http
->send_buffer
;
1918 http
->send_buffer
= NULL
; /* clear the pointer */
1921 if(HTTPREQ_POST_FORM
== data
->set
.httpreq
) {
1922 data
->req
.bytecount
= http
->readbytecount
+ http
->writebytecount
;
1924 Curl_formclean(&http
->sendit
); /* Now free that whole lot */
1926 /* a file being uploaded was left opened, close it! */
1927 fclose(http
->form
.fp
);
1928 http
->form
.fp
= NULL
;
1931 else if(HTTPREQ_PUT
== data
->set
.httpreq
)
1932 data
->req
.bytecount
= http
->readbytecount
+ http
->writebytecount
;
1934 if(status
!= CURLE_OK
)
1937 if(!premature
&& /* this check is pointless when DONE is called before the
1938 entire operation is complete */
1939 !conn
->bits
.retry
&&
1940 ((http
->readbytecount
+
1941 data
->req
.headerbytecount
-
1942 data
->req
.deductheadercount
)) <= 0) {
1943 /* If this connection isn't simply closed to be retried, AND nothing was
1944 read from the HTTP server (that counts), this can't be right so we
1945 return an error here */
1946 failf(data
, "Empty reply from server");
1947 return CURLE_GOT_NOTHING
;
1953 /* check and possibly add an Expect: header */
1954 static CURLcode
expect100(struct SessionHandle
*data
,
1955 send_buffer
*req_buffer
)
1957 CURLcode result
= CURLE_OK
;
1958 data
->state
.expect100header
= FALSE
; /* default to false unless it is set
1960 if((data
->set
.httpversion
!= CURL_HTTP_VERSION_1_0
) &&
1961 !checkheaders(data
, "Expect:")) {
1962 /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect:
1963 100-continue to the headers which actually speeds up post
1964 operations (as there is one packet coming back from the web
1966 result
= add_bufferf(req_buffer
,
1967 "Expect: 100-continue\r\n");
1968 if(result
== CURLE_OK
)
1969 data
->state
.expect100header
= TRUE
;
1974 static CURLcode
add_custom_headers(struct connectdata
*conn
,
1975 send_buffer
*req_buffer
)
1978 struct curl_slist
*headers
=conn
->data
->set
.headers
;
1981 ptr
= strchr(headers
->data
, ':');
1983 /* we require a colon for this to be a true header */
1985 ptr
++; /* pass the colon */
1986 while(*ptr
&& ISSPACE(*ptr
))
1990 /* only send this if the contents was non-blank */
1992 if(conn
->allocptr
.host
&&
1993 /* a Host: header was sent already, don't pass on any custom Host:
1994 header as that will produce *two* in the same request! */
1995 curl_strnequal("Host:", headers
->data
, 5))
1997 else if(conn
->data
->set
.httpreq
== HTTPREQ_POST_FORM
&&
1998 /* this header (extended by formdata.c) is sent later */
1999 curl_strnequal("Content-Type:", headers
->data
,
2000 strlen("Content-Type:")))
2003 CURLcode result
= add_bufferf(req_buffer
, "%s\r\n", headers
->data
);
2009 headers
= headers
->next
;
2015 * Curl_http() gets called from the generic Curl_do() function when a HTTP
2016 * request is to be performed. This creates and sends a properly constructed
2019 CURLcode
Curl_http(struct connectdata
*conn
, bool *done
)
2021 struct SessionHandle
*data
=conn
->data
;
2022 char *buf
= data
->state
.buffer
; /* this is a short cut to the buffer */
2023 CURLcode result
=CURLE_OK
;
2025 char *ppath
= data
->state
.path
;
2026 char ftp_typecode
[sizeof(";type=?")] = "";
2027 char *host
= conn
->host
.name
;
2028 const char *te
= ""; /* transfer-encoding */
2031 Curl_HttpReq httpreq
= data
->set
.httpreq
;
2032 char *addcookies
= NULL
;
2033 curl_off_t included_body
= 0;
2034 const char *httpstring
;
2035 send_buffer
*req_buffer
;
2036 curl_off_t postsize
; /* off_t type to be able to hold a large file size */
2039 /* Always consider the DO phase done after this function call, even if there
2040 may be parts of the request that is not yet sent, since we can deal with
2041 the rest of the request in the PERFORM phase. */
2044 /* If there already is a protocol-specific struct allocated for this
2045 sessionhandle, deal with it */
2046 Curl_reset_reqproto(conn
);
2048 if(!data
->state
.proto
.http
) {
2049 /* Only allocate this struct if we don't already have it! */
2051 http
= (struct HTTP
*)calloc(sizeof(struct HTTP
), 1);
2053 return CURLE_OUT_OF_MEMORY
;
2054 data
->state
.proto
.http
= http
;
2057 http
= data
->state
.proto
.http
;
2059 if( (conn
->protocol
&(PROT_HTTP
|PROT_FTP
)) &&
2061 httpreq
= HTTPREQ_PUT
;
2064 /* Now set the 'request' pointer to the proper request string */
2065 if(data
->set
.str
[STRING_CUSTOMREQUEST
])
2066 request
= data
->set
.str
[STRING_CUSTOMREQUEST
];
2068 if(data
->set
.opt_no_body
)
2069 request
= (char *)"HEAD";
2071 DEBUGASSERT((httpreq
> HTTPREQ_NONE
) && (httpreq
< HTTPREQ_LAST
));
2074 case HTTPREQ_POST_FORM
:
2075 request
= (char *)"POST";
2078 request
= (char *)"PUT";
2080 default: /* this should never happen */
2082 request
= (char *)"GET";
2085 request
= (char *)"HEAD";
2091 /* The User-Agent string might have been allocated in url.c already, because
2092 it might have been used in the proxy connect, but if we have got a header
2093 with the user-agent string specified, we erase the previously made string
2095 if(checkheaders(data
, "User-Agent:") && conn
->allocptr
.uagent
) {
2096 free(conn
->allocptr
.uagent
);
2097 conn
->allocptr
.uagent
=NULL
;
2100 /* setup the authentication headers */
2101 result
= http_output_auth(conn
, request
, ppath
, FALSE
);
2105 if((data
->state
.authhost
.multi
|| data
->state
.authproxy
.multi
) &&
2106 (httpreq
!= HTTPREQ_GET
) &&
2107 (httpreq
!= HTTPREQ_HEAD
)) {
2108 /* Auth is required and we are not authenticated yet. Make a PUT or POST
2109 with content-length zero as a "probe". */
2110 conn
->bits
.authneg
= TRUE
;
2113 conn
->bits
.authneg
= FALSE
;
2115 Curl_safefree(conn
->allocptr
.ref
);
2116 if(data
->change
.referer
&& !checkheaders(data
, "Referer:"))
2117 conn
->allocptr
.ref
= aprintf("Referer: %s\r\n", data
->change
.referer
);
2119 conn
->allocptr
.ref
= NULL
;
2121 if(data
->set
.str
[STRING_COOKIE
] && !checkheaders(data
, "Cookie:"))
2122 addcookies
= data
->set
.str
[STRING_COOKIE
];
2124 if(!checkheaders(data
, "Accept-Encoding:") &&
2125 data
->set
.str
[STRING_ENCODING
]) {
2126 Curl_safefree(conn
->allocptr
.accept_encoding
);
2127 conn
->allocptr
.accept_encoding
=
2128 aprintf("Accept-Encoding: %s\r\n", data
->set
.str
[STRING_ENCODING
]);
2129 if(!conn
->allocptr
.accept_encoding
)
2130 return CURLE_OUT_OF_MEMORY
;
2133 ptr
= checkheaders(data
, "Transfer-Encoding:");
2135 /* Some kind of TE is requested, check if 'chunked' is chosen */
2136 data
->req
.upload_chunky
=
2137 Curl_compareheader(ptr
, "Transfer-Encoding:", "chunked");
2140 if((conn
->protocol
&PROT_HTTP
) &&
2142 (data
->set
.infilesize
== -1) &&
2143 (data
->set
.httpversion
!= CURL_HTTP_VERSION_1_0
)) {
2144 /* HTTP, upload, unknown file size and not HTTP 1.0 */
2145 data
->req
.upload_chunky
= TRUE
;
2148 /* else, no chunky upload */
2149 data
->req
.upload_chunky
= FALSE
;
2152 if(data
->req
.upload_chunky
)
2153 te
= "Transfer-Encoding: chunked\r\n";
2156 Curl_safefree(conn
->allocptr
.host
);
2158 ptr
= checkheaders(data
, "Host:");
2159 if(ptr
&& (!data
->state
.this_is_a_follow
||
2160 curl_strequal(data
->state
.first_host
, conn
->host
.name
))) {
2161 #if !defined(CURL_DISABLE_COOKIES)
2162 /* If we have a given custom Host: header, we extract the host name in
2163 order to possibly use it for cookie reasons later on. We only allow the
2164 custom Host: header if this is NOT a redirect, as setting Host: in the
2165 redirected request is being out on thin ice. Except if the host name
2166 is the same as the first one! */
2167 char *cookiehost
= Curl_copy_header_value(ptr
);
2169 return CURLE_OUT_OF_MEMORY
;
2171 /* ignore empty data */
2174 char *colon
= strchr(cookiehost
, ':');
2176 *colon
= 0; /* The host must not include an embedded port number */
2177 Curl_safefree(conn
->allocptr
.cookiehost
);
2178 conn
->allocptr
.cookiehost
= cookiehost
;
2182 conn
->allocptr
.host
= NULL
;
2185 /* When building Host: headers, we must put the host name within
2186 [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
2188 if(((conn
->protocol
&PROT_HTTPS
) && (conn
->remote_port
== PORT_HTTPS
)) ||
2189 (!(conn
->protocol
&PROT_HTTPS
) && (conn
->remote_port
== PORT_HTTP
)) )
2190 /* if(HTTPS on port 443) OR (non-HTTPS on port 80) then don't include
2191 the port number in the host string */
2192 conn
->allocptr
.host
= aprintf("Host: %s%s%s\r\n",
2193 conn
->bits
.ipv6_ip
?"[":"",
2195 conn
->bits
.ipv6_ip
?"]":"");
2197 conn
->allocptr
.host
= aprintf("Host: %s%s%s:%d\r\n",
2198 conn
->bits
.ipv6_ip
?"[":"",
2200 conn
->bits
.ipv6_ip
?"]":"",
2203 if(!conn
->allocptr
.host
)
2204 /* without Host: we can't make a nice request */
2205 return CURLE_OUT_OF_MEMORY
;
2208 if(conn
->bits
.httpproxy
&& !conn
->bits
.tunnel_proxy
) {
2209 /* Using a proxy but does not tunnel through it */
2211 /* The path sent to the proxy is in fact the entire URL. But if the remote
2212 host is a IDN-name, we must make sure that the request we produce only
2213 uses the encoded host name! */
2214 if(conn
->host
.dispname
!= conn
->host
.name
) {
2215 char *url
= data
->change
.url
;
2216 ptr
= strstr(url
, conn
->host
.dispname
);
2218 /* This is where the display name starts in the URL, now replace this
2219 part with the encoded name. TODO: This method of replacing the host
2220 name is rather crude as I believe there's a slight risk that the
2221 user has entered a user name or password that contain the host name
2223 size_t currlen
= strlen(conn
->host
.dispname
);
2224 size_t newlen
= strlen(conn
->host
.name
);
2225 size_t urllen
= strlen(url
);
2229 newurl
= malloc(urllen
+ newlen
- currlen
+ 1);
2231 /* copy the part before the host name */
2232 memcpy(newurl
, url
, ptr
- url
);
2233 /* append the new host name instead of the old */
2234 memcpy(newurl
+ (ptr
- url
), conn
->host
.name
, newlen
);
2235 /* append the piece after the host name */
2236 memcpy(newurl
+ newlen
+ (ptr
- url
),
2237 ptr
+ currlen
, /* copy the trailing zero byte too */
2238 urllen
- (ptr
-url
) - currlen
+ 1);
2239 if(data
->change
.url_alloc
)
2240 free(data
->change
.url
);
2241 data
->change
.url
= newurl
;
2242 data
->change
.url_alloc
= TRUE
;
2245 return CURLE_OUT_OF_MEMORY
;
2248 ppath
= data
->change
.url
;
2249 if (data
->set
.proxy_transfer_mode
) {
2250 /* when doing ftp, append ;type=<a|i> if not present */
2251 if(checkprefix("ftp://", ppath
) || checkprefix("ftps://", ppath
)) {
2252 char *p
= strstr(ppath
, ";type=");
2253 if(p
&& p
[6] && p
[7] == 0) {
2254 switch (toupper((int)((unsigned char)p
[6]))) {
2264 snprintf(ftp_typecode
, sizeof(ftp_typecode
), ";type=%c",
2265 data
->set
.prefer_ascii
? 'a' : 'i');
2269 if(HTTPREQ_POST_FORM
== httpreq
) {
2270 /* we must build the whole darned post sequence first, so that we have
2271 a size of the whole shebang before we start to send it */
2272 result
= Curl_getFormData(&http
->sendit
, data
->set
.httppost
,
2273 checkheaders(data
, "Content-Type:"),
2275 if(CURLE_OK
!= result
) {
2276 /* Curl_getFormData() doesn't use failf() */
2277 failf(data
, "failed creating formpost data");
2284 (!checkheaders(data
, "Pragma:") &&
2285 (conn
->bits
.httpproxy
&& !conn
->bits
.tunnel_proxy
) )?
2286 "Pragma: no-cache\r\n":NULL
;
2288 http
->p_accept
= checkheaders(data
, "Accept:")?NULL
:"Accept: */*\r\n";
2290 if(( (HTTPREQ_POST
== httpreq
) ||
2291 (HTTPREQ_POST_FORM
== httpreq
) ||
2292 (HTTPREQ_PUT
== httpreq
) ) &&
2293 data
->state
.resume_from
) {
2294 /**********************************************************************
2295 * Resuming upload in HTTP means that we PUT or POST and that we have
2296 * got a resume_from value set. The resume value has already created
2297 * a Range: header that will be passed along. We need to "fast forward"
2298 * the file the given number of bytes and decrease the assume upload
2299 * file size before we continue this venture in the dark lands of HTTP.
2300 *********************************************************************/
2302 if(data
->state
.resume_from
< 0 ) {
2304 * This is meant to get the size of the present remote-file by itself.
2305 * We don't support this now. Bail out!
2307 data
->state
.resume_from
= 0;
2310 if(data
->state
.resume_from
&& !data
->state
.this_is_a_follow
) {
2311 /* do we still game? */
2313 /* Now, let's read off the proper amount of bytes from the
2315 if(conn
->seek_func
) {
2316 curl_off_t readthisamountnow
= data
->state
.resume_from
;
2318 if(conn
->seek_func(conn
->seek_client
,
2319 readthisamountnow
, SEEK_SET
) != 0) {
2320 failf(data
, "Could not seek stream");
2321 return CURLE_READ_ERROR
;
2325 curl_off_t passed
=0;
2328 size_t readthisamountnow
= (size_t)(data
->state
.resume_from
- passed
);
2329 size_t actuallyread
;
2331 if(readthisamountnow
> BUFSIZE
)
2332 readthisamountnow
= BUFSIZE
;
2334 actuallyread
= data
->set
.fread_func(data
->state
.buffer
, 1,
2335 (size_t)readthisamountnow
,
2338 passed
+= actuallyread
;
2339 if(actuallyread
!= readthisamountnow
) {
2340 failf(data
, "Could only read %" FORMAT_OFF_T
2341 " bytes from the input",
2343 return CURLE_READ_ERROR
;
2345 } while(passed
!= data
->state
.resume_from
); /* loop until done */
2348 /* now, decrease the size of the read */
2349 if(data
->set
.infilesize
>0) {
2350 data
->set
.infilesize
-= data
->state
.resume_from
;
2352 if(data
->set
.infilesize
<= 0) {
2353 failf(data
, "File already completely uploaded");
2354 return CURLE_PARTIAL_FILE
;
2357 /* we've passed, proceed as normal */
2360 if(data
->state
.use_range
) {
2362 * A range is selected. We use different headers whether we're downloading
2363 * or uploading and we always let customized headers override our internal
2364 * ones if any such are specified.
2366 if(((httpreq
== HTTPREQ_GET
) || (httpreq
== HTTPREQ_HEAD
)) &&
2367 !checkheaders(data
, "Range:")) {
2368 /* if a line like this was already allocated, free the previous one */
2369 if(conn
->allocptr
.rangeline
)
2370 free(conn
->allocptr
.rangeline
);
2371 conn
->allocptr
.rangeline
= aprintf("Range: bytes=%s\r\n",
2374 else if((httpreq
!= HTTPREQ_GET
) &&
2375 !checkheaders(data
, "Content-Range:")) {
2377 /* if a line like this was already allocated, free the previous one */
2378 if(conn
->allocptr
.rangeline
)
2379 free(conn
->allocptr
.rangeline
);
2381 if(data
->set
.set_resume_from
< 0) {
2382 /* Upload resume was asked for, but we don't know the size of the
2383 remote part so we tell the server (and act accordingly) that we
2384 upload the whole file (again) */
2385 conn
->allocptr
.rangeline
=
2386 aprintf("Content-Range: bytes 0-%" FORMAT_OFF_T
2387 "/%" FORMAT_OFF_T
"\r\n",
2388 data
->set
.infilesize
- 1, data
->set
.infilesize
);
2391 else if(data
->state
.resume_from
) {
2392 /* This is because "resume" was selected */
2393 curl_off_t total_expected_size
=
2394 data
->state
.resume_from
+ data
->set
.infilesize
;
2395 conn
->allocptr
.rangeline
=
2396 aprintf("Content-Range: bytes %s%" FORMAT_OFF_T
2397 "/%" FORMAT_OFF_T
"\r\n",
2398 data
->state
.range
, total_expected_size
-1,
2399 total_expected_size
);
2402 /* Range was selected and then we just pass the incoming range and
2403 append total size */
2404 conn
->allocptr
.rangeline
=
2405 aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T
"\r\n",
2406 data
->state
.range
, data
->set
.infilesize
);
2408 if(!conn
->allocptr
.rangeline
)
2409 return CURLE_OUT_OF_MEMORY
;
2413 /* Use 1.1 unless the use specificly asked for 1.0 */
2414 httpstring
= data
->set
.httpversion
==CURL_HTTP_VERSION_1_0
?"1.0":"1.1";
2416 /* initialize a dynamic send-buffer */
2417 req_buffer
= add_buffer_init();
2420 return CURLE_OUT_OF_MEMORY
;
2422 /* add the main request stuff */
2424 add_bufferf(req_buffer
,
2425 "%s " /* GET/HEAD/POST/PUT */
2426 "%s%s HTTP/%s\r\n" /* path + HTTP version */
2427 "%s" /* proxyuserpwd */
2430 "%s" /* user agent */
2434 "%s" /* accept-encoding */
2436 "%s" /* Proxy-Connection */
2437 "%s",/* transfer-encoding */
2443 conn
->allocptr
.proxyuserpwd
?
2444 conn
->allocptr
.proxyuserpwd
:"",
2445 conn
->allocptr
.userpwd
?conn
->allocptr
.userpwd
:"",
2446 (data
->state
.use_range
&& conn
->allocptr
.rangeline
)?
2447 conn
->allocptr
.rangeline
:"",
2448 (data
->set
.str
[STRING_USERAGENT
] &&
2449 *data
->set
.str
[STRING_USERAGENT
] && conn
->allocptr
.uagent
)?
2450 conn
->allocptr
.uagent
:"",
2451 (conn
->allocptr
.host
?conn
->allocptr
.host
:""), /* Host: host */
2452 http
->p_pragma
?http
->p_pragma
:"",
2453 http
->p_accept
?http
->p_accept
:"",
2454 (data
->set
.str
[STRING_ENCODING
] &&
2455 *data
->set
.str
[STRING_ENCODING
] &&
2456 conn
->allocptr
.accept_encoding
)?
2457 conn
->allocptr
.accept_encoding
:"",
2458 (data
->change
.referer
&& conn
->allocptr
.ref
)?
2459 conn
->allocptr
.ref
:"" /* Referer: <data> */,
2460 (conn
->bits
.httpproxy
&&
2461 !conn
->bits
.tunnel_proxy
&&
2462 !checkheaders(data
, "Proxy-Connection:"))?
2463 "Proxy-Connection: Keep-Alive\r\n":"",
2468 * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM
2469 * with basic and digest, it will be freed anyway by the next request
2472 Curl_safefree (conn
->allocptr
.userpwd
);
2473 conn
->allocptr
.userpwd
= NULL
;
2478 #if !defined(CURL_DISABLE_COOKIES)
2479 if(data
->cookies
|| addcookies
) {
2480 struct Cookie
*co
=NULL
; /* no cookies from start */
2484 Curl_share_lock(data
, CURL_LOCK_DATA_COOKIE
, CURL_LOCK_ACCESS_SINGLE
);
2485 co
= Curl_cookie_getlist(data
->cookies
,
2486 conn
->allocptr
.cookiehost
?
2487 conn
->allocptr
.cookiehost
:host
,
2489 (bool)(conn
->protocol
&PROT_HTTPS
?TRUE
:FALSE
));
2490 Curl_share_unlock(data
, CURL_LOCK_DATA_COOKIE
);
2493 struct Cookie
*store
=co
;
2494 /* now loop through all cookies that matched */
2498 result
= add_bufferf(req_buffer
, "Cookie: ");
2502 result
= add_bufferf(req_buffer
,
2503 "%s%s=%s", count
?"; ":"",
2504 co
->name
, co
->value
);
2509 co
= co
->next
; /* next cookie please */
2511 Curl_cookie_freelist(store
, FALSE
); /* free the cookie list */
2513 if(addcookies
&& (CURLE_OK
== result
)) {
2515 result
= add_bufferf(req_buffer
, "Cookie: ");
2516 if(CURLE_OK
== result
) {
2517 result
= add_bufferf(req_buffer
, "%s%s",
2523 if(count
&& (CURLE_OK
== result
))
2524 result
= add_buffer(req_buffer
, "\r\n", 2);
2531 if(data
->set
.timecondition
) {
2534 /* The If-Modified-Since header family should have their times set in
2535 * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be
2536 * represented in Greenwich Mean Time (GMT), without exception. For the
2537 * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal
2538 * Time)." (see page 20 of RFC2616).
2541 #ifdef HAVE_GMTIME_R
2542 /* thread-safe version */
2544 tm
= (struct tm
*)gmtime_r(&data
->set
.timevalue
, &keeptime
);
2546 tm
= gmtime(&data
->set
.timevalue
);
2549 /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
2550 snprintf(buf
, BUFSIZE
-1,
2551 "%s, %02d %s %4d %02d:%02d:%02d GMT",
2552 Curl_wkday
[tm
->tm_wday
?tm
->tm_wday
-1:6],
2554 Curl_month
[tm
->tm_mon
],
2560 switch(data
->set
.timecondition
) {
2561 case CURL_TIMECOND_IFMODSINCE
:
2563 result
= add_bufferf(req_buffer
,
2564 "If-Modified-Since: %s\r\n", buf
);
2566 case CURL_TIMECOND_IFUNMODSINCE
:
2567 result
= add_bufferf(req_buffer
,
2568 "If-Unmodified-Since: %s\r\n", buf
);
2570 case CURL_TIMECOND_LASTMOD
:
2571 result
= add_bufferf(req_buffer
,
2572 "Last-Modified: %s\r\n", buf
);
2579 result
= add_custom_headers(conn
, req_buffer
);
2583 http
->postdata
= NULL
; /* nothing to post at this point */
2584 Curl_pgrsSetUploadSize(data
, 0); /* upload size is 0 atm */
2586 /* If 'authdone' is FALSE, we must not set the write socket index to the
2587 Curl_transfer() call below, as we're not ready to actually upload any
2592 case HTTPREQ_POST_FORM
:
2593 if(!http
->sendit
|| conn
->bits
.authneg
) {
2594 /* nothing to post! */
2595 result
= add_bufferf(req_buffer
, "Content-Length: 0\r\n\r\n");
2599 result
= add_buffer_send(req_buffer
, conn
,
2600 &data
->info
.request_size
, 0, FIRSTSOCKET
);
2602 failf(data
, "Failed sending POST request");
2604 /* setup variables for the upcoming transfer */
2605 result
= Curl_setup_transfer(conn
, FIRSTSOCKET
, -1, TRUE
,
2606 &http
->readbytecount
,
2611 if(Curl_FormInit(&http
->form
, http
->sendit
)) {
2612 failf(data
, "Internal HTTP POST error!");
2613 return CURLE_HTTP_POST_ERROR
;
2616 /* Get the currently set callback function pointer and store that in the
2617 form struct since we might want the actual user-provided callback later
2618 on. The conn->fread_func pointer itself will be changed for the
2619 multipart case to the function that returns a multipart formatted
2621 http
->form
.fread_func
= conn
->fread_func
;
2623 /* Set the read function to read from the generated form data */
2624 conn
->fread_func
= (curl_read_callback
)Curl_FormReader
;
2625 conn
->fread_in
= &http
->form
;
2627 http
->sending
= HTTPSEND_BODY
;
2629 if(!data
->req
.upload_chunky
) {
2630 /* only add Content-Length if not uploading chunked */
2631 result
= add_bufferf(req_buffer
,
2632 "Content-Length: %" FORMAT_OFF_T
"\r\n",
2638 result
= expect100(data
, req_buffer
);
2644 /* Get Content-Type: line from Curl_formpostheader.
2647 size_t linelength
=0;
2648 contentType
= Curl_formpostheader((void *)&http
->form
,
2651 failf(data
, "Could not get Content-Type header line!");
2652 return CURLE_HTTP_POST_ERROR
;
2655 result
= add_buffer(req_buffer
, contentType
, linelength
);
2660 /* make the request end in a true CRLF */
2661 result
= add_buffer(req_buffer
, "\r\n", 2);
2665 /* set upload size to the progress meter */
2666 Curl_pgrsSetUploadSize(data
, http
->postsize
);
2668 /* fire away the whole request to the server */
2669 result
= add_buffer_send(req_buffer
, conn
,
2670 &data
->info
.request_size
, 0, FIRSTSOCKET
);
2672 failf(data
, "Failed sending POST request");
2674 /* setup variables for the upcoming transfer */
2675 result
= Curl_setup_transfer(conn
, FIRSTSOCKET
, -1, TRUE
,
2676 &http
->readbytecount
,
2678 &http
->writebytecount
);
2681 Curl_formclean(&http
->sendit
); /* free that whole lot */
2684 #ifdef CURL_DOES_CONVERSIONS
2685 /* time to convert the form data... */
2686 result
= Curl_formconvert(data
, http
->sendit
);
2688 Curl_formclean(&http
->sendit
); /* free that whole lot */
2691 #endif /* CURL_DOES_CONVERSIONS */
2694 case HTTPREQ_PUT
: /* Let's PUT the data to the server! */
2696 if(conn
->bits
.authneg
)
2699 postsize
= data
->set
.infilesize
;
2701 if((postsize
!= -1) && !data
->req
.upload_chunky
) {
2702 /* only add Content-Length if not uploading chunked */
2703 result
= add_bufferf(req_buffer
,
2704 "Content-Length: %" FORMAT_OFF_T
"\r\n",
2710 result
= expect100(data
, req_buffer
);
2714 result
= add_buffer(req_buffer
, "\r\n", 2); /* end of headers */
2718 /* set the upload size to the progress meter */
2719 Curl_pgrsSetUploadSize(data
, postsize
);
2721 /* this sends the buffer and frees all the buffer resources */
2722 result
= add_buffer_send(req_buffer
, conn
,
2723 &data
->info
.request_size
, 0, FIRSTSOCKET
);
2725 failf(data
, "Failed sending PUT request");
2727 /* prepare for transfer */
2728 result
= Curl_setup_transfer(conn
, FIRSTSOCKET
, -1, TRUE
,
2729 &http
->readbytecount
,
2730 postsize
?FIRSTSOCKET
:-1,
2731 postsize
?&http
->writebytecount
:NULL
);
2737 /* this is the simple POST, using x-www-form-urlencoded style */
2739 if(conn
->bits
.authneg
)
2742 /* figure out the size of the postfields */
2743 postsize
= (data
->set
.postfieldsize
!= -1)?
2744 data
->set
.postfieldsize
:
2745 (data
->set
.postfields
? (curl_off_t
)strlen(data
->set
.postfields
):0);
2747 if(!data
->req
.upload_chunky
) {
2748 /* We only set Content-Length and allow a custom Content-Length if
2749 we don't upload data chunked, as RFC2616 forbids us to set both
2750 kinds of headers (Transfer-Encoding: chunked and Content-Length) */
2752 if(!checkheaders(data
, "Content-Length:")) {
2753 /* we allow replacing this header, although it isn't very wise to
2754 actually set your own */
2755 result
= add_bufferf(req_buffer
,
2756 "Content-Length: %" FORMAT_OFF_T
"\r\n",
2763 if(!checkheaders(data
, "Content-Type:")) {
2764 result
= add_bufferf(req_buffer
,
2765 "Content-Type: application/x-www-form-urlencoded\r\n");
2770 /* For really small posts we don't use Expect: headers at all, and for
2771 the somewhat bigger ones we allow the app to disable it. Just make
2772 sure that the expect100header is always set to the preferred value
2774 if(postsize
> TINY_INITIAL_POST_SIZE
) {
2775 result
= expect100(data
, req_buffer
);
2780 data
->state
.expect100header
= FALSE
;
2782 if(data
->set
.postfields
) {
2784 if(!data
->state
.expect100header
&&
2785 (postsize
< MAX_INITIAL_POST_SIZE
)) {
2786 /* if we don't use expect: 100 AND
2787 postsize is less than MAX_INITIAL_POST_SIZE
2789 then append the post data to the HTTP request header. This limit
2790 is no magic limit but only set to prevent really huge POSTs to
2791 get the data duplicated with malloc() and family. */
2793 result
= add_buffer(req_buffer
, "\r\n", 2); /* end of headers! */
2797 if(!data
->req
.upload_chunky
) {
2798 /* We're not sending it 'chunked', append it to the request
2799 already now to reduce the number if send() calls */
2800 result
= add_buffer(req_buffer
, data
->set
.postfields
,
2802 included_body
= postsize
;
2805 /* Append the POST data chunky-style */
2806 result
= add_bufferf(req_buffer
, "%x\r\n", (int)postsize
);
2807 if(CURLE_OK
== result
)
2808 result
= add_buffer(req_buffer
, data
->set
.postfields
,
2810 if(CURLE_OK
== result
)
2811 result
= add_buffer(req_buffer
,
2812 "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7);
2813 /* CR LF 0 CR LF CR LF */
2814 included_body
= postsize
+ 7;
2820 /* A huge POST coming up, do data separate from the request */
2821 http
->postsize
= postsize
;
2822 http
->postdata
= data
->set
.postfields
;
2824 http
->sending
= HTTPSEND_BODY
;
2826 conn
->fread_func
= (curl_read_callback
)readmoredata
;
2827 conn
->fread_in
= (void *)conn
;
2829 /* set the upload size to the progress meter */
2830 Curl_pgrsSetUploadSize(data
, http
->postsize
);
2832 result
= add_buffer(req_buffer
, "\r\n", 2); /* end of headers! */
2838 result
= add_buffer(req_buffer
, "\r\n", 2); /* end of headers! */
2842 if(data
->set
.postfieldsize
) {
2843 /* set the upload size to the progress meter */
2844 Curl_pgrsSetUploadSize(data
, postsize
?postsize
:-1);
2846 /* set the pointer to mark that we will send the post body using the
2847 read callback, but only if we're not in authenticate
2849 if(!conn
->bits
.authneg
) {
2850 http
->postdata
= (char *)&http
->postdata
;
2851 http
->postsize
= postsize
;
2855 /* issue the request */
2856 result
= add_buffer_send(req_buffer
, conn
, &data
->info
.request_size
,
2857 (size_t)included_body
, FIRSTSOCKET
);
2860 failf(data
, "Failed sending HTTP POST request");
2863 Curl_setup_transfer(conn
, FIRSTSOCKET
, -1, TRUE
,
2864 &http
->readbytecount
,
2865 http
->postdata
?FIRSTSOCKET
:-1,
2866 http
->postdata
?&http
->writebytecount
:NULL
);
2870 result
= add_buffer(req_buffer
, "\r\n", 2);
2874 /* issue the request */
2875 result
= add_buffer_send(req_buffer
, conn
,
2876 &data
->info
.request_size
, 0, FIRSTSOCKET
);
2879 failf(data
, "Failed sending HTTP request");
2881 /* HTTP GET/HEAD download: */
2882 result
= Curl_setup_transfer(conn
, FIRSTSOCKET
, -1, TRUE
,
2883 &http
->readbytecount
,
2884 http
->postdata
?FIRSTSOCKET
:-1,
2885 http
->postdata
?&http
->writebytecount
:NULL
);
2890 if(http
->writebytecount
) {
2891 /* if a request-body has been sent off, we make sure this progress is noted
2893 Curl_pgrsSetUploadCounter(data
, http
->writebytecount
);
2894 if(Curl_pgrsUpdate(conn
))
2895 result
= CURLE_ABORTED_BY_CALLBACK
;