1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2004, 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.204 2004/03/14 18:15:04 bagder Exp $
22 ***************************************************************************/
26 #ifndef CURL_DISABLE_HTTP
27 /* -- WIN32 approved -- */
33 #include <sys/types.h>
38 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
42 #ifdef HAVE_SYS_SOCKET_H
43 #include <sys/socket.h>
45 #ifdef HAVE_NETINET_IN_H
46 #include <netinet/in.h>
51 #ifdef TIME_WITH_SYS_TIME
60 #ifdef HAVE_ARPA_INET_H
61 #include <arpa/inet.h>
66 #include <sys/ioctl.h>
69 #ifdef HAVE_SYS_PARAM_H
70 #include <sys/param.h>
73 #ifdef HAVE_SYS_SELECT_H
74 #include <sys/select.h>
81 #include <curl/curl.h>
90 #include "http_digest.h"
91 #include "http_ntlm.h"
92 #include "http_negotiate.h"
97 #define _MPRINTF_REPLACE /* use our functions only */
98 #include <curl/mprintf.h>
100 /* The last #include file should be: */
102 #include "memdebug.h"
105 static CURLcode Curl_output_basic_proxy(struct connectdata *conn);
108 * This function checks the linked list of custom HTTP headers for a particular
111 static char *checkheaders(struct SessionHandle *data, const char *thisheader)
113 struct curl_slist *head;
114 size_t thislen = strlen(thisheader);
116 for(head = data->set.headers; head; head=head->next) {
117 if(strnequal(head->data, thisheader, thislen))
123 static CURLcode Curl_output_basic(struct connectdata *conn)
126 struct SessionHandle *data=conn->data;
128 sprintf(data->state.buffer, "%s:%s", conn->user, conn->passwd);
129 if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer),
130 &authorization) > 0) {
131 if(conn->allocptr.userpwd)
132 free(conn->allocptr.userpwd);
133 conn->allocptr.userpwd = aprintf( "Authorization: Basic %s\015\012",
138 return CURLE_OUT_OF_MEMORY;
142 static CURLcode Curl_output_basic_proxy(struct connectdata *conn)
145 struct SessionHandle *data=conn->data;
147 sprintf(data->state.buffer, "%s:%s",
148 conn->proxyuser, conn->proxypasswd);
149 if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer),
150 &authorization) > 0) {
151 Curl_safefree(conn->allocptr.proxyuserpwd);
152 conn->allocptr.proxyuserpwd =
153 aprintf("Proxy-authorization: Basic %s\015\012", authorization);
157 return CURLE_OUT_OF_MEMORY;
162 * Curl_http_auth_act() checks what authentication methods that are available
163 * and decides which one (if any) to use. It will set 'newurl' if an auth
167 void Curl_http_auth_act(struct connectdata *conn)
169 struct SessionHandle *data = conn->data;
171 if(data->state.authavail) {
172 /* The order of these checks is highly relevant, as this will be the order
173 of preference in case of the existance of multiple accepted types. */
174 if(data->state.authavail & CURLAUTH_GSSNEGOTIATE)
175 data->state.authwant = CURLAUTH_GSSNEGOTIATE;
176 else if(data->state.authavail & CURLAUTH_DIGEST)
177 data->state.authwant = CURLAUTH_DIGEST;
178 else if(data->state.authavail & CURLAUTH_NTLM)
179 data->state.authwant = CURLAUTH_NTLM;
180 else if(data->state.authavail & CURLAUTH_BASIC)
181 data->state.authwant = CURLAUTH_BASIC;
183 data->state.authwant = CURLAUTH_NONE; /* clear it */
185 if(data->state.authwant)
186 conn->newurl = strdup(data->change.url); /* clone URL */
187 data->state.authavail = CURLAUTH_NONE; /* clear it here */
192 * Setup the authentication headers for the host/proxy and the correct
193 * authentication method.
196 static CURLcode http_auth_headers(struct connectdata *conn,
199 bool *ready) /* set TRUE when the auth phase
200 is done and ready to do the *actual*
203 CURLcode result = CURLE_OK;
204 struct SessionHandle *data = conn->data;
207 *ready = FALSE; /* default is no */
209 if(!data->state.authstage) {
210 if(conn->bits.httpproxy && conn->bits.proxy_user_passwd)
211 Curl_http_auth_stage(data, 407);
212 else if(conn->bits.user_passwd)
213 Curl_http_auth_stage(data, 401);
216 return CURLE_OK; /* no authentication with no user or password */
220 /* To prevent the user+password to get sent to other than the original
221 host due to a location-follow, we do some weirdo checks here */
222 if(!data->state.this_is_a_follow ||
223 !data->state.auth_host ||
224 curl_strequal(data->state.auth_host, conn->hostname) ||
225 data->set.http_disable_hostname_check_before_authentication) {
227 /* Send proxy authentication header if needed */
228 if (data->state.authstage == 407) {
230 if(data->state.authwant == CURLAUTH_NTLM) {
232 result = Curl_output_ntlm(conn, TRUE, ready);
238 if(data->state.authwant == CURLAUTH_BASIC) {
240 if(conn->bits.proxy_user_passwd &&
241 !checkheaders(data, "Proxy-authorization:")) {
242 auth=(char *)"Basic";
243 result = Curl_output_basic_proxy(conn);
248 /* Switch to web authentication after proxy authentication is done */
249 Curl_http_auth_stage(data, 401);
251 infof(data, "Proxy auth using %s with user '%s'\n",
252 auth, conn->proxyuser?conn->proxyuser:"");
254 /* Send web authentication header if needed */
255 if (data->state.authstage == 401) {
258 if((data->state.authwant == CURLAUTH_GSSNEGOTIATE) &&
259 data->state.negotiate.context &&
260 !GSS_ERROR(data->state.negotiate.status)) {
261 auth=(char *)"GSS-Negotiate";
262 result = Curl_output_negotiate(conn);
270 if(data->state.authwant == CURLAUTH_NTLM) {
272 result = Curl_output_ntlm(conn, FALSE, ready);
279 if((data->state.authwant == CURLAUTH_DIGEST) &&
280 data->state.digest.nonce) {
281 auth=(char *)"Digest";
282 result = Curl_output_digest(conn,
283 (unsigned char *)request,
284 (unsigned char *)path);
289 else if(data->state.authwant == CURLAUTH_BASIC) {/* Basic */
290 if(conn->bits.user_passwd &&
291 !checkheaders(data, "Authorization:")) {
292 auth=(char *)"Basic";
293 result = Curl_output_basic(conn);
297 /* basic is always ready */
302 infof(data, "Server auth using %s with user '%s'\n",
314 * Curl_http_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
315 * headers. They are dealt with both in the transfer.c main loop and in the
316 * proxy CONNECT loop.
319 CURLcode Curl_http_auth(struct connectdata *conn,
321 char *header) /* pointing to the first non-space */
324 * This resource requires authentication
326 struct SessionHandle *data = conn->data;
331 if (httpcode == 407) {
332 start = header+strlen("Proxy-authenticate:");
333 availp = &data->info.proxyauthavail;
336 start = header+strlen("WWW-Authenticate:");
337 availp = &data->info.httpauthavail;
340 * Switch from proxy to web authentication and back if needed
342 if (httpcode == 407 && data->state.authstage != 407)
343 Curl_http_auth_stage(data, 407);
345 else if (httpcode == 401 && data->state.authstage != 401)
346 Curl_http_auth_stage(data, 401);
348 /* pass all white spaces */
349 while(*start && isspace((int)*start))
353 * Here we check if we want the specific single authentiction (using ==) and
354 * if we do, we initiate usage of it.
356 * If the provided authentication is wanted as one out of several accepted
357 * types (using &), we OR this authenticaion type to the authavail
362 if (checkprefix("GSS-Negotiate", start) ||
363 checkprefix("Negotiate", start)) {
364 *availp |= CURLAUTH_GSSNEGOTIATE;
365 if(data->state.authwant == CURLAUTH_GSSNEGOTIATE) {
366 /* if exactly this is wanted, go */
367 int neg = Curl_input_negotiate(conn, start);
369 conn->newurl = strdup(data->change.url);
372 if(data->state.authwant & CURLAUTH_GSSNEGOTIATE)
373 data->state.authavail |= CURLAUTH_GSSNEGOTIATE;
378 /* NTLM support requires the SSL crypto libs */
379 if(checkprefix("NTLM", start)) {
380 *availp |= CURLAUTH_NTLM;
381 if(data->state.authwant == CURLAUTH_NTLM) {
382 /* NTLM authentication is activated */
384 Curl_input_ntlm(conn, (bool)(httpcode == 407), start);
386 if(CURLNTLM_BAD != ntlm)
387 conn->newurl = strdup(data->change.url); /* clone string */
389 infof(data, "Authentication problem. Ignoring this.\n");
392 if(data->state.authwant & CURLAUTH_NTLM)
393 data->state.authavail |= CURLAUTH_NTLM;
397 if(checkprefix("Digest", start)) {
398 *availp |= CURLAUTH_DIGEST;
399 if(data->state.authwant == CURLAUTH_DIGEST) {
400 /* Digest authentication is activated */
401 CURLdigest dig = CURLDIGEST_BAD;
403 if(data->state.digest.nonce)
404 infof(data, "Authentication problem. Ignoring this.\n");
406 dig = Curl_input_digest(conn, start);
408 if(CURLDIGEST_FINE == dig)
409 /* We act on it. Store our new url, which happens to be
410 the same one we already use! */
411 conn->newurl = strdup(data->change.url); /* clone string */
414 if(data->state.authwant & CURLAUTH_DIGEST) {
415 /* We don't know if Digest is what we're gonna use, but we
416 call this function anyway to store the digest data that
417 is provided on this line, to skip the extra round-trip
418 we need to do otherwise. We must sure to free this
420 Curl_input_digest(conn, start);
421 data->state.authavail |= CURLAUTH_DIGEST;
424 else if(checkprefix("Basic", start)) {
425 *availp |= CURLAUTH_BASIC;
426 if((data->state.authwant == CURLAUTH_BASIC) &&
427 (httpcode == data->state.authstage)) {
428 /* We asked for Basic authentication but got a 40X back
429 anyway, which basicly means our name+password isn't
431 data->state.authavail = CURLAUTH_NONE;
432 infof(data, "Authentication problem. Ignoring this.\n");
434 else if(data->state.authwant & CURLAUTH_BASIC) {
435 data->state.authavail |= CURLAUTH_BASIC;
442 /* fread() emulation to provide POST and/or request data */
443 static size_t readmoredata(char *buffer,
448 struct connectdata *conn = (struct connectdata *)userp;
449 struct HTTP *http = conn->proto.http;
450 size_t fullsize = size * nitems;
452 if(0 == http->postsize)
453 /* nothing to return */
456 /* make sure that a HTTP request is never sent away chunked! */
457 conn->bits.forbidchunk= (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
459 if(http->postsize <= (curl_off_t)fullsize) {
460 memcpy(buffer, http->postdata, (size_t)http->postsize);
461 fullsize = (size_t)http->postsize;
463 if(http->backup.postsize) {
464 /* move backup data into focus and continue on that */
465 http->postdata = http->backup.postdata;
466 http->postsize = http->backup.postsize;
467 conn->fread = http->backup.fread;
468 conn->fread_in = http->backup.fread_in;
470 http->sending++; /* move one step up */
472 http->backup.postsize=0;
480 memcpy(buffer, http->postdata, fullsize);
481 http->postdata += fullsize;
482 http->postsize -= fullsize;
487 /* ------------------------------------------------------------------------- */
489 * The add_buffer series of functions are used to build one large memory chunk
490 * from repeated function invokes. Used so that the entire HTTP request can
499 typedef struct send_buffer send_buffer;
502 add_buffer(send_buffer *in, const void *inptr, size_t size);
505 * add_buffer_init() returns a fine buffer struct
508 send_buffer *add_buffer_init(void)
511 blonk=(send_buffer *)malloc(sizeof(send_buffer));
513 memset(blonk, 0, sizeof(send_buffer));
516 return NULL; /* failed, go home */
520 * add_buffer_send() sends a buffer and frees all associated memory.
523 CURLcode add_buffer_send(send_buffer *in,
524 struct connectdata *conn,
525 long *bytes_written) /* add the number of sent
526 bytes to this counter */
532 struct HTTP *http = conn->proto.http;
534 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
536 /* The looping below is required since we use non-blocking sockets, but due
537 to the circumstances we will just loop and try again and again etc */
540 size = in->size_used;
542 if(conn->protocol & PROT_HTTPS) {
543 /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
544 when we speak HTTPS, as if only a fraction of it is sent now, this data
545 needs to fit into the normal read-callback buffer later on and that
546 buffer is using this size.
549 sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:size;
551 /* OpenSSL is very picky and we must send the SAME buffer pointer to the
552 library when we attempt to re-send this buffer. Sending the same data
553 is not enough, we must use the exact same address. For this reason, we
554 must copy the data to the uploadbuffer first, since that is the buffer
555 we will be using if this send is retried later.
557 memcpy(conn->data->state.uploadbuffer, ptr, sendsize);
558 ptr = conn->data->state.uploadbuffer;
563 res = Curl_write(conn, sockfd, ptr, sendsize, &amount);
565 if(CURLE_OK == res) {
567 if(conn->data->set.verbose)
568 /* this data _may_ contain binary stuff */
569 Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, amount);
571 *bytes_written += amount;
573 if((size_t)amount != size) {
574 /* The whole request could not be sent in one system call. We must queue
575 it up and send it later when we get the chance. We must not loop here
576 and wait until it might work again. */
580 ptr = in->buffer + amount;
582 /* backup the currently set pointers */
583 http->backup.fread = conn->fread;
584 http->backup.fread_in = conn->fread_in;
585 http->backup.postdata = http->postdata;
586 http->backup.postsize = http->postsize;
588 /* set the new pointers for the request-sending */
589 conn->fread = (curl_read_callback)readmoredata;
590 conn->fread_in = (void *)conn;
591 http->postdata = ptr;
592 http->postsize = size;
594 http->send_buffer = in;
595 http->sending = HTTPSEND_REQUEST;
599 http->sending = HTTPSEND_BODY;
600 /* the full buffer was sent, clean up and return */
611 * add_bufferf() builds a buffer from the formatted input
614 CURLcode add_bufferf(send_buffer *in, const char *fmt, ...)
619 s = vaprintf(fmt, ap); /* this allocs a new string to append */
623 CURLcode result = add_buffer(in, s, strlen(s));
625 if(CURLE_OK == result)
628 /* If we failed, we cleanup the whole buffer and return error */
632 return CURLE_OUT_OF_MEMORY;
636 * add_buffer() appends a memory chunk to the existing one
639 CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size)
645 ((in->size_used + size) > (in->size_max - 1))) {
646 new_size = (in->size_used+size)*2;
648 /* we have a buffer, enlarge the existing one */
649 new_rb = (char *)realloc(in->buffer, new_size);
651 /* create a new buffer */
652 new_rb = (char *)malloc(new_size);
655 return CURLE_OUT_OF_MEMORY;
658 in->size_max = new_size;
660 memcpy(&in->buffer[in->size_used], inptr, size);
662 in->size_used += size;
667 /* end of the add_buffer functions */
668 /* ------------------------------------------------------------------------- */
671 * Curl_compareheader()
673 * Returns TRUE if 'headerline' contains the 'header' with given 'content'.
674 * Pass headers WITH the colon.
677 Curl_compareheader(char *headerline, /* line to check */
678 const char *header, /* header keyword _with_ colon */
679 const char *content) /* content string to find */
681 /* RFC2616, section 4.2 says: "Each header field consists of a name followed
682 * by a colon (":") and the field value. Field names are case-insensitive.
683 * The field value MAY be preceded by any amount of LWS, though a single SP
686 size_t hlen = strlen(header);
692 if(!strnequal(headerline, header, hlen))
693 return FALSE; /* doesn't start with header */
695 /* pass the header */
696 start = &headerline[hlen];
698 /* pass all white spaces */
699 while(*start && isspace((int)*start))
702 /* find the end of the header line */
703 end = strchr(start, '\r'); /* lines end with CRLF */
705 /* in case there's a non-standard compliant line here */
706 end = strchr(start, '\n');
709 /* hm, there's no line ending here, use the zero byte! */
710 end = strchr(start, '\0');
713 len = end-start; /* length of the content part of the input line */
714 clen = strlen(content); /* length of the word to find */
716 /* find the content string in the rest of the line */
717 for(;len>=clen;len--, start++) {
718 if(strnequal(start, content, clen))
719 return TRUE; /* match! */
722 return FALSE; /* no match */
726 * ConnectHTTPProxyTunnel() requires that we're connected to a HTTP proxy. This
727 * function will issue the necessary commands to get a seamless tunnel through
728 * this proxy. After that, the socket can be used just as a normal socket.
731 CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
738 struct SessionHandle *data=conn->data;
742 size_t nread; /* total size read */
743 int perline; /* count bytes per line */
747 long timeout = 3600; /* default timeout in seconds */
748 struct timeval interval;
753 curl_socket_t tunnelsocket = conn->sock[sockindex];
756 #define SELECT_ERROR 1
757 #define SELECT_TIMEOUT 2
758 int error = SELECT_OK;
760 infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
763 bool auth; /* we don't really have to know when the auth phase is done,
764 but this variable will be set to true then */
767 /* This only happens if we've looped here due to authentication reasons,
768 and we don't really use the newly cloned URL here then. Just free()
774 host_port = aprintf("%s:%d", hostname, remote_port);
776 return CURLE_OUT_OF_MEMORY;
778 /* Setup the proxy-authorization header, if any */
779 result = http_auth_headers(conn, (char *)"CONNECT", host_port, &auth);
780 if(CURLE_OK == result) {
782 /* OK, now send the connect request to the proxy */
784 Curl_sendf(tunnelsocket, conn,
785 "CONNECT %s:%d HTTP/1.0\015\012"
789 hostname, remote_port,
790 conn->bits.proxy_user_passwd?
791 conn->allocptr.proxyuserpwd:"",
792 data->set.useragent?conn->allocptr.uagent:""
795 failf(data, "Failed sending CONNECT to proxy");
801 FD_ZERO (&readfd); /* clear it */
802 FD_SET (tunnelsocket, &readfd); /* read socket */
804 /* get this in a backup variable to be able to restore it on each lap in
808 ptr=data->state.buffer;
815 while((nread<BUFSIZE) && (keepon && !error)) {
816 readfd = rkeepfd; /* set every lap */
817 interval.tv_sec = 1; /* timeout each second and check the timeout */
818 interval.tv_usec = 0;
820 if(data->set.timeout) {
821 /* if timeout is requested, find out how much remaining time we have */
822 timeout = data->set.timeout - /* timeout time */
823 Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
825 failf(data, "Proxy connection aborted due to timeout");
826 error = SELECT_TIMEOUT; /* already too little time */
831 switch (select (tunnelsocket+1, &readfd, NULL, NULL, &interval)) {
832 case -1: /* select() error, stop reading */
833 error = SELECT_ERROR;
834 failf(data, "Proxy CONNECT aborted due to select() error");
836 case 0: /* timeout */
840 * This code previously didn't use the kerberos sec_read() code
841 * to read, but when we use Curl_read() it may do so. Do confirm
842 * that this is still ok and then remove this comment!
844 res= Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes);
847 continue; /* go loop yourself */
850 else if(gotbytes <= 0) {
852 error = SELECT_ERROR;
853 failf(data, "Proxy CONNECT aborted");
857 * We got a whole chunk of data, which can be anything from one byte
858 * to a set of lines and possibly just a piece of the last line.
860 * TODO: To make this code work less error-prone, we need to make
861 * sure that we read and create full lines before we compare them,
862 * as there is really nothing that stops the proxy from delivering
863 * the response lines in multiple parts, each part consisting of
864 * only a little piece of the line(s). */
868 for(i = 0; i < gotbytes; ptr++, i++) {
869 perline++; /* amount of bytes in this line so far */
874 /* output debug output if that is requested */
875 if(data->set.verbose)
876 Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline);
878 /* send the header to the callback */
879 writetype = CLIENTWRITE_HEADER;
880 if(data->set.http_include_header)
881 writetype |= CLIENTWRITE_BODY;
883 result = Curl_client_write(data, writetype, line_start, perline);
887 /* Newlines are CRLF, so the CR is ignored as the line isn't
888 really terminated until the LF comes. Treat a following CR
889 as end-of-headers as well.*/
891 if(('\r' == line_start[0]) ||
892 ('\n' == line_start[0])) {
893 /* end of response-headers from the proxy */
895 break; /* breaks out of for-loop, not switch() */
898 /* keep a backup of the position we are about to blank */
899 letter = line_start[perline];
900 line_start[perline]=0; /* zero terminate the buffer */
901 if((checkprefix("WWW-Authenticate:", line_start) &&
902 (401 == httpcode)) ||
903 (checkprefix("Proxy-authenticate:", line_start) &&
904 (407 == httpcode))) {
905 result = Curl_http_auth(conn, httpcode, line_start);
909 else if(2 == sscanf(line_start, "HTTP/1.%d %d",
912 /* store the HTTP code */
913 data->info.httpproxycode = httpcode;
915 /* put back the letter we blanked out before */
916 line_start[perline]= letter;
918 perline=0; /* line starts over here */
919 line_start = ptr+1; /* this skips the zero byte we wrote */
925 } /* while there's buffer left and loop is requested */
928 return CURLE_RECV_ERROR;
930 /* Deal with the possibly already received authenticate headers. 'newurl'
931 is set to a new URL if we must loop. */
932 Curl_http_auth_act(conn);
934 } while(conn->newurl);
936 if(200 != httpcode) {
937 failf(data, "Received HTTP code %d from proxy after CONNECT", httpcode);
938 return CURLE_RECV_ERROR;
941 /* If a proxy-authorization header was used for the proxy, then we should
942 make sure that it isn't accidentally used for the document request
943 after we've connected. So let's free and clear it here. */
944 Curl_safefree(conn->allocptr.proxyuserpwd);
945 conn->allocptr.proxyuserpwd = NULL;
947 Curl_http_auth_stage(data, 401); /* move on to the host auth */
949 infof (data, "Proxy replied OK to CONNECT request\n");
954 * HTTP stuff to do at connect-time.
956 CURLcode Curl_http_connect(struct connectdata *conn)
958 struct SessionHandle *data;
963 /* If we are not using a proxy and we want a secure connection,
964 * perform SSL initialization & connection now.
965 * If using a proxy with https, then we must tell the proxy to CONNECT
966 * us to the host we want to talk to. Only after the connect
967 * has occured, can we start talking SSL
970 if(conn->bits.httpproxy &&
971 ((conn->protocol & PROT_HTTPS) || data->set.tunnel_thru_httpproxy)) {
973 /* either HTTPS over proxy, OR explicitly asked for a tunnel */
974 result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET,
975 conn->hostname, conn->remote_port);
976 if(CURLE_OK != result)
980 if(conn->protocol & PROT_HTTPS) {
981 /* now, perform the SSL initialization for this socket */
982 result = Curl_SSLConnect(conn, FIRSTSOCKET);
987 if(conn->bits.user_passwd && !data->state.this_is_a_follow) {
988 /* Authorization: is requested, this is not a followed location, get the
989 original host name */
990 if (data->state.auth_host)
991 /* Free to avoid leaking memory on multiple requests*/
992 free(data->state.auth_host);
994 data->state.auth_host = strdup(conn->hostname);
1000 CURLcode Curl_http_done(struct connectdata *conn)
1002 struct SessionHandle *data;
1006 http=conn->proto.http;
1008 /* set the proper values (possibly modified on POST) */
1009 conn->fread = data->set.fread; /* restore */
1010 conn->fread_in = data->set.in; /* restore */
1015 if(http->send_buffer) {
1016 send_buffer *buff = http->send_buffer;
1020 http->send_buffer = NULL; /* cleaer the pointer */
1023 if(HTTPREQ_POST_FORM == data->set.httpreq) {
1024 conn->bytecount = http->readbytecount + http->writebytecount;
1026 Curl_formclean(http->sendit); /* Now free that whole lot */
1028 else if(HTTPREQ_PUT == data->set.httpreq)
1029 conn->bytecount = http->readbytecount + http->writebytecount;
1031 if(!conn->bits.retry &&
1032 !(http->readbytecount + conn->headerbytecount)) {
1033 /* If this connection isn't simply closed to be retried, AND nothing was
1034 read from the HTTP server, this can't be right so we return an error
1036 failf(data, "Empty reply from server");
1037 return CURLE_GOT_NOTHING;
1043 void Curl_http_auth_stage(struct SessionHandle *data,
1046 curlassert((stage == 401) || (stage == 407));
1048 /* We set none, one or more bits for which authentication types we accept
1050 data->state.authwant = (stage == 401)?
1051 data->set.httpauth:data->set.proxyauth;
1053 data->state.authstage = stage;
1054 data->state.authavail = CURLAUTH_NONE; /* no type available yet */
1057 CURLcode Curl_http(struct connectdata *conn)
1059 struct SessionHandle *data=conn->data;
1060 char *buf = data->state.buffer; /* this is a short cut to the buffer */
1061 CURLcode result=CURLE_OK;
1063 struct Cookie *co=NULL; /* no cookies from start */
1064 char *ppath = conn->ppath; /* three previous function arguments */
1065 char *host = conn->name;
1066 const char *te = ""; /* tranfer-encoding */
1069 bool authdone=TRUE; /* if the authentication phase is done */
1071 if(!conn->proto.http) {
1072 /* Only allocate this struct if we don't already have it! */
1074 http = (struct HTTP *)malloc(sizeof(struct HTTP));
1076 return CURLE_OUT_OF_MEMORY;
1077 memset(http, 0, sizeof(struct HTTP));
1078 conn->proto.http = http;
1081 http = conn->proto.http;
1083 /* We default to persistant connections */
1084 conn->bits.close = FALSE;
1086 if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) &&
1088 data->set.httpreq = HTTPREQ_PUT;
1091 request = data->set.customrequest?
1092 data->set.customrequest:
1093 (data->set.no_body?(char *)"HEAD":
1094 ((HTTPREQ_POST == data->set.httpreq) ||
1095 (HTTPREQ_POST_FORM == data->set.httpreq))?(char *)"POST":
1096 (HTTPREQ_PUT == data->set.httpreq)?(char *)"PUT":(char *)"GET");
1098 /* The User-Agent string has been built in url.c already, because it might
1099 have been used in the proxy connect, but if we have got a header with
1100 the user-agent string specified, we erase the previously made string
1102 if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
1103 free(conn->allocptr.uagent);
1104 conn->allocptr.uagent=NULL;
1107 /* setup the authentication headers */
1108 result = http_auth_headers(conn, request, ppath, &authdone);
1112 Curl_safefree(conn->allocptr.ref);
1113 if(data->change.referer && !checkheaders(data, "Referer:"))
1114 conn->allocptr.ref = aprintf("Referer: %s\015\012", data->change.referer);
1116 conn->allocptr.ref = NULL;
1118 Curl_safefree(conn->allocptr.cookie);
1119 if(data->set.cookie && !checkheaders(data, "Cookie:"))
1120 conn->allocptr.cookie = aprintf("Cookie: %s\015\012", data->set.cookie);
1122 conn->allocptr.cookie = NULL;
1124 if(!conn->bits.upload_chunky && (data->set.httpreq != HTTPREQ_GET)) {
1125 /* not a chunky transfer yet, but data is to be sent */
1126 ptr = checkheaders(data, "Transfer-Encoding:");
1128 /* Some kind of TE is requested, check if 'chunked' is chosen */
1129 conn->bits.upload_chunky =
1130 Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
1134 else if(conn->bits.upload_chunky) {
1135 /* RFC2616 section 4.4:
1136 Messages MUST NOT include both a Content-Length header field and a
1137 non-identity transfer-coding. If the message does include a non-
1138 identity transfer-coding, the Content-Length MUST be ignored. */
1140 if(!checkheaders(data, "Transfer-Encoding:")) {
1141 te = "Transfer-Encoding: chunked\r\n";
1145 conn->bits.upload_chunky = FALSE; /* transfer-encoding was disabled,
1146 so don't chunkify this! */
1150 ptr = checkheaders(data, "Host:");
1151 if(ptr && !data->state.this_is_a_follow) {
1152 /* If we have a given custom Host: header, we extract the host name in
1153 order to possibly use it for cookie reasons later on. We only allow the
1154 custom Host: header if this is NOT a redirect, as setting Host: in the
1155 redirected request is being out on thin ice. */
1156 char *start = ptr+strlen("Host:");
1157 while(*start && isspace((int)*start ))
1159 ptr = start; /* start host-scanning here */
1161 /* scan through the string to find the end (space or colon) */
1162 while(*ptr && !isspace((int)*ptr) && !(':'==*ptr))
1166 size_t len=ptr-start;
1167 conn->allocptr.cookiehost = malloc(len+1);
1168 if(!conn->allocptr.cookiehost)
1169 return CURLE_OUT_OF_MEMORY;
1170 memcpy(conn->allocptr.cookiehost, start, len);
1171 conn->allocptr.cookiehost[len]=0;
1175 Curl_safefree(conn->allocptr.host);
1177 /* When building Host: headers, we must put the host name within
1178 [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
1180 if(((conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTPS)) ||
1181 (!(conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTP)) )
1182 /* If (HTTPS on port 443) OR (non-HTTPS on port 80) then don't include
1183 the port number in the host string */
1184 conn->allocptr.host = aprintf("Host: %s%s%s\r\n",
1185 conn->bits.ipv6_ip?"[":"",
1187 conn->bits.ipv6_ip?"]":"");
1189 conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n",
1190 conn->bits.ipv6_ip?"[":"",
1192 conn->bits.ipv6_ip?"]":"",
1195 if(!conn->allocptr.host)
1196 /* without Host: we can't make a nice request */
1197 return CURLE_OUT_OF_MEMORY;
1201 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
1202 co = Curl_cookie_getlist(data->cookies,
1203 conn->allocptr.cookiehost?
1204 conn->allocptr.cookiehost:host, ppath,
1205 (bool)(conn->protocol&PROT_HTTPS?TRUE:FALSE));
1206 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
1209 if (conn->bits.httpproxy &&
1210 !data->set.tunnel_thru_httpproxy &&
1211 !(conn->protocol&PROT_HTTPS)) {
1212 /* The path sent to the proxy is in fact the entire URL */
1213 ppath = data->change.url;
1215 if(HTTPREQ_POST_FORM == data->set.httpreq) {
1216 /* we must build the whole darned post sequence first, so that we have
1217 a size of the whole shebang before we start to send it */
1218 result = Curl_getFormData(&http->sendit, data->set.httppost,
1220 if(CURLE_OK != result) {
1221 /* Curl_getFormData() doesn't use failf() */
1222 failf(data, "failed creating formpost data");
1228 if(!checkheaders(data, "Pragma:"))
1229 http->p_pragma = "Pragma: no-cache\r\n";
1231 if(!checkheaders(data, "Accept:"))
1232 http->p_accept = "Accept: */*\r\n";
1234 if(( (HTTPREQ_POST == data->set.httpreq) ||
1235 (HTTPREQ_POST_FORM == data->set.httpreq) ||
1236 (HTTPREQ_PUT == data->set.httpreq) ) &&
1237 conn->resume_from) {
1238 /**********************************************************************
1239 * Resuming upload in HTTP means that we PUT or POST and that we have
1240 * got a resume_from value set. The resume value has already created
1241 * a Range: header that will be passed along. We need to "fast forward"
1242 * the file the given number of bytes and decrease the assume upload
1243 * file size before we continue this venture in the dark lands of HTTP.
1244 *********************************************************************/
1246 if(conn->resume_from < 0 ) {
1248 * This is meant to get the size of the present remote-file by itself.
1249 * We don't support this now. Bail out!
1251 conn->resume_from = 0;
1254 if(conn->resume_from) {
1255 /* do we still game? */
1256 curl_off_t passed=0;
1258 /* Now, let's read off the proper amount of bytes from the
1259 input. If we knew it was a proper file we could've just
1260 fseek()ed but we only have a stream here */
1262 size_t readthisamountnow = (size_t)(conn->resume_from - passed);
1263 size_t actuallyread;
1265 if(readthisamountnow > BUFSIZE)
1266 readthisamountnow = BUFSIZE;
1269 data->set.fread(data->state.buffer, 1, (size_t)readthisamountnow,
1272 passed += actuallyread;
1273 if(actuallyread != readthisamountnow) {
1274 failf(data, "Could only read %" FORMAT_OFF_T
1275 " bytes from the input",
1277 return CURLE_READ_ERROR;
1279 } while(passed != conn->resume_from); /* loop until done */
1281 /* now, decrease the size of the read */
1282 if(data->set.infilesize>0) {
1283 data->set.infilesize -= conn->resume_from;
1285 if(data->set.infilesize <= 0) {
1286 failf(data, "File already completely uploaded");
1287 return CURLE_PARTIAL_FILE;
1290 /* we've passed, proceed as normal */
1293 if(conn->bits.use_range) {
1295 * A range is selected. We use different headers whether we're downloading
1296 * or uploading and we always let customized headers override our internal
1297 * ones if any such are specified.
1299 if((data->set.httpreq == HTTPREQ_GET) &&
1300 !checkheaders(data, "Range:")) {
1301 /* if a line like this was already allocated, free the previous one */
1302 if(conn->allocptr.rangeline)
1303 free(conn->allocptr.rangeline);
1304 conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", conn->range);
1306 else if((data->set.httpreq != HTTPREQ_GET) &&
1307 !checkheaders(data, "Content-Range:")) {
1309 if(conn->resume_from) {
1310 /* This is because "resume" was selected */
1311 curl_off_t total_expected_size=
1312 conn->resume_from + data->set.infilesize;
1313 conn->allocptr.rangeline =
1314 aprintf("Content-Range: bytes %s%" FORMAT_OFF_T
1315 "/%" FORMAT_OFF_T "\r\n",
1316 conn->range, total_expected_size-1,
1317 total_expected_size);
1320 /* Range was selected and then we just pass the incoming range and
1321 append total size */
1322 conn->allocptr.rangeline =
1323 aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n",
1324 conn->range, data->set.infilesize);
1330 /* Use 1.1 unless the use specificly asked for 1.0 */
1331 const char *httpstring=
1332 data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1";
1334 send_buffer *req_buffer;
1335 struct curl_slist *headers=data->set.headers;
1336 curl_off_t postsize; /* off_t type to be able to hold a large file size */
1338 /* initialize a dynamic send-buffer */
1339 req_buffer = add_buffer_init();
1342 return CURLE_OUT_OF_MEMORY;
1344 /* add the main request stuff */
1346 add_bufferf(req_buffer,
1347 "%s " /* GET/HEAD/POST/PUT */
1348 "%s HTTP/%s\r\n" /* path + HTTP version */
1349 "%s" /* proxyuserpwd */
1352 "%s" /* user agent */
1357 "%s" /* accept-encoding */
1359 "%s",/* transfer-encoding */
1364 (conn->bits.httpproxy && conn->allocptr.proxyuserpwd)?
1365 conn->allocptr.proxyuserpwd:"",
1366 conn->allocptr.userpwd?conn->allocptr.userpwd:"",
1367 (conn->bits.use_range && conn->allocptr.rangeline)?
1368 conn->allocptr.rangeline:"",
1369 (data->set.useragent && *data->set.useragent && conn->allocptr.uagent)?
1370 conn->allocptr.uagent:"",
1371 (conn->allocptr.cookie?conn->allocptr.cookie:""), /* Cookie: <data> */
1372 (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */
1373 http->p_pragma?http->p_pragma:"",
1374 http->p_accept?http->p_accept:"",
1375 (data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)?
1376 conn->allocptr.accept_encoding:"", /* 08/28/02 jhrg */
1377 (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: <data> <CRLF> */,
1386 struct Cookie *store=co;
1387 /* now loop through all cookies that matched */
1391 add_bufferf(req_buffer, "Cookie: ");
1393 add_bufferf(req_buffer,
1394 "%s%s=%s", count?"; ":"", co->name, co->value);
1397 co = co->next; /* next cookie please */
1400 add_buffer(req_buffer, "\r\n", 2);
1402 Curl_cookie_freelist(store); /* free the cookie list */
1406 if(data->set.timecondition) {
1407 struct tm *thistime;
1409 /* Phil Karn (Fri, 13 Apr 2001) pointed out that the If-Modified-Since
1410 * header family should have their times set in GMT as RFC2616 defines:
1411 * "All HTTP date/time stamps MUST be represented in Greenwich Mean Time
1412 * (GMT), without exception. For the purposes of HTTP, GMT is exactly
1413 * equal to UTC (Coordinated Universal Time)." (see page 20 of RFC2616).
1416 #ifdef HAVE_GMTIME_R
1417 /* thread-safe version */
1419 thistime = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
1421 thistime = gmtime(&data->set.timevalue);
1424 #ifdef HAVE_STRFTIME
1425 /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
1426 strftime(buf, BUFSIZE-1, "%a, %d %b %Y %H:%M:%S GMT", thistime);
1428 /* TODO: Right, we *could* write a replacement here */
1429 strcpy(buf, "no strftime() support");
1431 switch(data->set.timecondition) {
1432 case CURL_TIMECOND_IFMODSINCE:
1434 add_bufferf(req_buffer,
1435 "If-Modified-Since: %s\r\n", buf);
1437 case CURL_TIMECOND_IFUNMODSINCE:
1438 add_bufferf(req_buffer,
1439 "If-Unmodified-Since: %s\r\n", buf);
1441 case CURL_TIMECOND_LASTMOD:
1442 add_bufferf(req_buffer,
1443 "Last-Modified: %s\r\n", buf);
1449 ptr = strchr(headers->data, ':');
1451 /* we require a colon for this to be a true header */
1453 ptr++; /* pass the colon */
1454 while(*ptr && isspace((int)*ptr))
1458 /* only send this if the contents was non-blank */
1460 add_bufferf(req_buffer, "%s\r\n", headers->data);
1463 headers = headers->next;
1466 http->postdata = NULL; /* nothing to post at this point */
1467 Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
1469 /* If 'authdone' is still FALSE, we must not set the write socket index to
1470 the Curl_transfer() call below, as we're not ready to actually upload
1473 switch(data->set.httpreq) {
1475 case HTTPREQ_POST_FORM:
1476 if(Curl_FormInit(&http->form, http->sendit)) {
1477 failf(data, "Internal HTTP POST error!");
1478 return CURLE_HTTP_POST_ERROR;
1481 /* set the read function to read from the generated form data */
1482 conn->fread = (curl_read_callback)Curl_FormReader;
1483 conn->fread_in = &http->form;
1485 http->sending = HTTPSEND_BODY;
1487 if(!conn->bits.upload_chunky)
1488 /* only add Content-Length if not uploading chunked */
1489 add_bufferf(req_buffer,
1490 "Content-Length: %" FORMAT_OFF_T "\r\n", http->postsize);
1492 if(!checkheaders(data, "Expect:")) {
1493 /* if not disabled explicitly we add a Expect: 100-continue
1494 to the headers which actually speeds up post operations (as
1495 there is one packet coming back from the web server) */
1496 add_bufferf(req_buffer,
1497 "Expect: 100-continue\r\n");
1498 data->set.expect100header = TRUE;
1501 if(!checkheaders(data, "Content-Type:")) {
1502 /* Get Content-Type: line from Curl_FormReadOneLine, which happens
1503 to always be the first line. We can know this for sure since
1504 we always build the formpost linked list the same way!
1506 The Content-Type header line also contains the MIME boundary
1507 string etc why disabling this header is likely to not make things
1508 work, but we support it anyway.
1510 char contentType[256];
1511 size_t linelength=0;
1512 linelength = Curl_FormReadOneLine(contentType,
1513 sizeof(contentType),
1515 (FILE *)&http->form);
1517 failf(data, "Could not get Content-Type header line!");
1518 return CURLE_HTTP_POST_ERROR;
1520 add_buffer(req_buffer, contentType, linelength);
1523 /* make the request end in a true CRLF */
1524 add_buffer(req_buffer, "\r\n", 2);
1526 /* set upload size to the progress meter */
1527 Curl_pgrsSetUploadSize(data, http->postsize);
1529 /* fire away the whole request to the server */
1530 result = add_buffer_send(req_buffer, conn,
1531 &data->info.request_size);
1533 failf(data, "Failed sending POST request");
1535 /* setup variables for the upcoming transfer */
1536 result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
1537 &http->readbytecount,
1538 authdone?FIRSTSOCKET:-1,
1539 authdone?&http->writebytecount:NULL);
1541 Curl_formclean(http->sendit); /* free that whole lot */
1546 case HTTPREQ_PUT: /* Let's PUT the data to the server! */
1548 if((data->set.infilesize>0) && !conn->bits.upload_chunky)
1549 /* only add Content-Length if not uploading chunked */
1550 add_bufferf(req_buffer,
1551 "Content-Length: %" FORMAT_OFF_T "\r\n", /* size */
1552 data->set.infilesize );
1554 if(!checkheaders(data, "Expect:")) {
1555 /* if not disabled explicitly we add a Expect: 100-continue
1556 to the headers which actually speeds up post operations (as
1557 there is one packet coming back from the web server) */
1558 add_bufferf(req_buffer,
1559 "Expect: 100-continue\r\n");
1560 data->set.expect100header = TRUE;
1563 add_buffer(req_buffer, "\r\n", 2); /* end of headers */
1565 /* set the upload size to the progress meter */
1566 Curl_pgrsSetUploadSize(data, data->set.infilesize);
1568 /* this sends the buffer and frees all the buffer resources */
1569 result = add_buffer_send(req_buffer, conn,
1570 &data->info.request_size);
1572 failf(data, "Failed sending POST request");
1574 /* prepare for transfer */
1575 result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
1576 &http->readbytecount,
1577 authdone?FIRSTSOCKET:-1,
1578 authdone?&http->writebytecount:NULL);
1584 /* this is the simple POST, using x-www-form-urlencoded style */
1586 /* store the size of the postfields */
1587 postsize = data->set.postfieldsize?
1588 data->set.postfieldsize:
1589 (data->set.postfields?(curl_off_t)strlen(data->set.postfields):0);
1591 if(!conn->bits.upload_chunky) {
1592 /* We only set Content-Length and allow a custom Content-Length if
1593 we don't upload data chunked, as RFC2616 forbids us to set both
1594 kinds of headers (Transfer-Encoding: chunked and Content-Length) */
1596 if(!checkheaders(data, "Content-Length:"))
1597 /* we allow replacing this header, although it isn't very wise to
1598 actually set your own */
1599 add_bufferf(req_buffer, "Content-Length: %" FORMAT_OFF_T"\r\n",
1603 if(!checkheaders(data, "Content-Type:"))
1604 add_bufferf(req_buffer,
1605 "Content-Type: application/x-www-form-urlencoded\r\n");
1607 if(data->set.postfields) {
1609 if(authdone && (postsize < (100*1024))) {
1610 /* If we're not done with the authentication phase, we don't expect
1611 to actually send off any data yet. Hence, we delay the sending of
1612 the body until we receive that friendly 100-continue response */
1614 /* The post data is less than 100K, then append it to the header.
1615 This limit is no magic limit but only set to prevent really huge
1616 POSTs to get the data duplicated with malloc() and family. */
1618 add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
1620 if(!conn->bits.upload_chunky)
1621 /* We're not sending it 'chunked', append it to the request
1622 already now to reduce the number if send() calls */
1623 add_buffer(req_buffer, data->set.postfields, (size_t)postsize);
1625 /* Append the POST data chunky-style */
1626 add_bufferf(req_buffer, "%x\r\n", (int)postsize);
1627 add_buffer(req_buffer, data->set.postfields, (size_t)postsize);
1628 add_buffer(req_buffer, "\r\n0\r\n\r\n", 7); /* end of a chunked
1633 /* A huge POST coming up, do data separate from the request */
1634 http->postsize = postsize;
1635 http->postdata = data->set.postfields;
1637 http->sending = HTTPSEND_BODY;
1639 conn->fread = (curl_read_callback)readmoredata;
1640 conn->fread_in = (void *)conn;
1642 /* set the upload size to the progress meter */
1643 Curl_pgrsSetUploadSize(data, http->postsize);
1645 if(!authdone && !checkheaders(data, "Expect:")) {
1646 /* if not disabled explicitly we add a Expect: 100-continue to the
1647 headers which actually speeds up post operations (as there is
1648 one packet coming back from the web server) */
1649 add_bufferf(req_buffer,
1650 "Expect: 100-continue\r\n");
1651 data->set.expect100header = TRUE;
1654 add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
1658 add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
1660 /* set the upload size to the progress meter */
1661 Curl_pgrsSetUploadSize(data, data->set.infilesize);
1663 /* set the pointer to mark that we will send the post body using
1664 the read callback */
1665 http->postdata = (char *)&http->postdata;
1667 /* issue the request */
1668 result = add_buffer_send(req_buffer, conn,
1669 &data->info.request_size);
1672 failf(data, "Failed sending HTTP POST request");
1675 Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
1676 &http->readbytecount,
1677 http->postdata?FIRSTSOCKET:-1,
1678 http->postdata?&http->writebytecount:NULL);
1682 add_buffer(req_buffer, "\r\n", 2);
1684 /* issue the request */
1685 result = add_buffer_send(req_buffer, conn,
1686 &data->info.request_size);
1689 failf(data, "Failed sending HTTP request");
1691 /* HTTP GET/HEAD download: */
1692 result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
1693 &http->readbytecount,
1694 http->postdata?FIRSTSOCKET:-1,
1695 http->postdata?&http->writebytecount:NULL);