Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Utilities / cmcurl / http.c
blobb604392812afa54fd55d71701638a46c319b6170
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2007, 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.2 2007/03/15 19:22:13 andy Exp $
22 ***************************************************************************/
24 #include "setup.h"
26 #ifndef CURL_DISABLE_HTTP
27 /* -- WIN32 approved -- */
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33 #ifdef HAVE_SYS_TYPES_H
34 #include <sys/types.h>
35 #endif
36 #ifdef HAVE_SYS_STAT_H
37 #include <sys/stat.h>
38 #endif
40 #ifdef WIN32
41 #include <time.h>
42 #include <io.h>
43 #else
44 #ifdef HAVE_SYS_SOCKET_H
45 #include <sys/socket.h>
46 #endif
47 #ifdef HAVE_NETINET_IN_H
48 #include <netinet/in.h>
49 #endif
50 #ifdef HAVE_SYS_TIME_H
51 #include <sys/time.h>
52 #endif
54 #ifdef HAVE_TIME_H
55 #ifdef TIME_WITH_SYS_TIME
56 #include <time.h>
57 #endif
58 #endif
60 #ifdef HAVE_UNISTD_H
61 #include <unistd.h>
62 #endif
63 #include <netdb.h>
64 #ifdef HAVE_ARPA_INET_H
65 #include <arpa/inet.h>
66 #endif
67 #ifdef HAVE_NET_IF_H
68 #include <net/if.h>
69 #endif
70 #include <sys/ioctl.h>
71 #include <signal.h>
73 #ifdef HAVE_SYS_PARAM_H
74 #include <sys/param.h>
75 #endif
77 #endif
79 #include "urldata.h"
80 #include <curl/curl.h>
81 #include "transfer.h"
82 #include "sendf.h"
83 #include "easyif.h" /* for Curl_convert_... prototypes */
84 #include "formdata.h"
85 #include "progress.h"
86 #include "base64.h"
87 #include "cookie.h"
88 #include "strequal.h"
89 #include "sslgen.h"
90 #include "http_digest.h"
91 #include "http_ntlm.h"
92 #include "http_negotiate.h"
93 #include "url.h"
94 #include "share.h"
95 #include "hostip.h"
96 #include "http.h"
97 #include "memory.h"
98 #include "select.h"
99 #include "parsedate.h" /* for the week day and month names */
100 #include "strtoofft.h"
101 #include "multiif.h"
103 #define _MPRINTF_REPLACE /* use our functions only */
104 #include <curl/mprintf.h>
106 /* The last #include file should be: */
107 #include "memdebug.h"
110 * checkheaders() checks the linked list of custom HTTP headers for a
111 * particular header (prefix).
113 * Returns a pointer to the first matching header or NULL if none matched.
115 static char *checkheaders(struct SessionHandle *data, const char *thisheader)
117 struct curl_slist *head;
118 size_t thislen = strlen(thisheader);
120 for(head = data->set.headers; head; head=head->next) {
121 if(strnequal(head->data, thisheader, thislen))
122 return head->data;
124 return NULL;
128 * Curl_output_basic() sets up an Authorization: header (or the proxy version)
129 * for HTTP Basic authentication.
131 * Returns CURLcode.
133 static CURLcode Curl_output_basic(struct connectdata *conn, bool proxy)
135 char *authorization;
136 struct SessionHandle *data=conn->data;
137 char **userp;
138 char *user;
139 char *pwd;
141 if(proxy) {
142 userp = &conn->allocptr.proxyuserpwd;
143 user = conn->proxyuser;
144 pwd = conn->proxypasswd;
146 else {
147 userp = &conn->allocptr.userpwd;
148 user = conn->user;
149 pwd = conn->passwd;
152 snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd);
153 if(Curl_base64_encode(data, data->state.buffer,
154 strlen(data->state.buffer),
155 &authorization) > 0) {
156 if(*userp)
157 free(*userp);
158 *userp = aprintf( "%sAuthorization: Basic %s\r\n",
159 proxy?"Proxy-":"",
160 authorization);
161 free(authorization);
163 else
164 return CURLE_OUT_OF_MEMORY;
165 return CURLE_OK;
168 /* pickoneauth() selects the most favourable authentication method from the
169 * ones available and the ones we want.
171 * return TRUE if one was picked
173 static bool pickoneauth(struct auth *pick)
175 bool picked;
176 /* only deal with authentication we want */
177 long avail = pick->avail & pick->want;
178 picked = TRUE;
180 /* The order of these checks is highly relevant, as this will be the order
181 of preference in case of the existance of multiple accepted types. */
182 if(avail & CURLAUTH_GSSNEGOTIATE)
183 pick->picked = CURLAUTH_GSSNEGOTIATE;
184 else if(avail & CURLAUTH_DIGEST)
185 pick->picked = CURLAUTH_DIGEST;
186 else if(avail & CURLAUTH_NTLM)
187 pick->picked = CURLAUTH_NTLM;
188 else if(avail & CURLAUTH_BASIC)
189 pick->picked = CURLAUTH_BASIC;
190 else {
191 pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */
192 picked = FALSE;
194 pick->avail = CURLAUTH_NONE; /* clear it here */
196 return picked;
200 * perhapsrewind()
202 * If we are doing POST or PUT {
203 * If we have more data to send {
204 * If we are doing NTLM {
205 * Keep sending since we must not disconnect
207 * else {
208 * If there is more than just a little data left to send, close
209 * the current connection by force.
212 * If we have sent any data {
213 * If we don't have track of all the data {
214 * call app to tell it to rewind
216 * else {
217 * rewind internally so that the operation can restart fine
222 static CURLcode perhapsrewind(struct connectdata *conn)
224 struct SessionHandle *data = conn->data;
225 struct HTTP *http = data->reqdata.proto.http;
226 struct Curl_transfer_keeper *k = &data->reqdata.keep;
227 curl_off_t bytessent;
228 curl_off_t expectsend = -1; /* default is unknown */
230 if(!http)
231 /* If this is still NULL, we have not reach very far and we can
232 safely skip this rewinding stuff */
233 return CURLE_OK;
235 bytessent = http->writebytecount;
237 if(conn->bits.authneg)
238 /* This is a state where we are known to be negotiating and we don't send
239 any data then. */
240 expectsend = 0;
241 else {
242 /* figure out how much data we are expected to send */
243 switch(data->set.httpreq) {
244 case HTTPREQ_POST:
245 if(data->set.postfieldsize != -1)
246 expectsend = data->set.postfieldsize;
247 break;
248 case HTTPREQ_PUT:
249 if(data->set.infilesize != -1)
250 expectsend = data->set.infilesize;
251 break;
252 case HTTPREQ_POST_FORM:
253 expectsend = http->postsize;
254 break;
255 default:
256 break;
260 conn->bits.rewindaftersend = FALSE; /* default */
262 if((expectsend == -1) || (expectsend > bytessent)) {
263 /* There is still data left to send */
264 if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
265 (data->state.authhost.picked == CURLAUTH_NTLM)) {
266 if(((expectsend - bytessent) < 2000) ||
267 (conn->ntlm.state != NTLMSTATE_NONE)) {
268 /* The NTLM-negotiation has started *OR* there is just a little (<2K)
269 data left to send, keep on sending. */
271 /* rewind data when completely done sending! */
272 if(!conn->bits.authneg)
273 conn->bits.rewindaftersend = TRUE;
275 return CURLE_OK;
277 if(conn->bits.close)
278 /* this is already marked to get closed */
279 return CURLE_OK;
281 infof(data, "NTLM send, close instead of sending %" FORMAT_OFF_T
282 " bytes\n", (curl_off_t)(expectsend - bytessent));
285 /* This is not NTLM or NTLM with many bytes left to send: close
287 conn->bits.close = TRUE;
288 k->size = 0; /* don't download any more than 0 bytes */
291 if(bytessent)
292 return Curl_readrewind(conn);
294 return CURLE_OK;
298 * Curl_http_auth_act() gets called when a all HTTP headers have been received
299 * and it checks what authentication methods that are available and decides
300 * which one (if any) to use. It will set 'newurl' if an auth metod was
301 * picked.
304 CURLcode Curl_http_auth_act(struct connectdata *conn)
306 struct SessionHandle *data = conn->data;
307 bool pickhost = FALSE;
308 bool pickproxy = FALSE;
309 CURLcode code = CURLE_OK;
311 if(100 == data->reqdata.keep.httpcode)
312 /* this is a transient response code, ignore */
313 return CURLE_OK;
315 if(data->state.authproblem)
316 return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
318 if(conn->bits.user_passwd &&
319 ((data->reqdata.keep.httpcode == 401) ||
320 (conn->bits.authneg && data->reqdata.keep.httpcode < 300))) {
321 pickhost = pickoneauth(&data->state.authhost);
322 if(!pickhost)
323 data->state.authproblem = TRUE;
325 if(conn->bits.proxy_user_passwd &&
326 ((data->reqdata.keep.httpcode == 407) ||
327 (conn->bits.authneg && data->reqdata.keep.httpcode < 300))) {
328 pickproxy = pickoneauth(&data->state.authproxy);
329 if(!pickproxy)
330 data->state.authproblem = TRUE;
333 if(pickhost || pickproxy) {
334 data->reqdata.newurl = strdup(data->change.url); /* clone URL */
336 if((data->set.httpreq != HTTPREQ_GET) &&
337 (data->set.httpreq != HTTPREQ_HEAD) &&
338 !conn->bits.rewindaftersend) {
339 code = perhapsrewind(conn);
340 if(code)
341 return code;
345 else if((data->reqdata.keep.httpcode < 300) &&
346 (!data->state.authhost.done) &&
347 conn->bits.authneg) {
348 /* no (known) authentication available,
349 authentication is not "done" yet and
350 no authentication seems to be required and
351 we didn't try HEAD or GET */
352 if((data->set.httpreq != HTTPREQ_GET) &&
353 (data->set.httpreq != HTTPREQ_HEAD)) {
354 data->reqdata.newurl = strdup(data->change.url); /* clone URL */
355 data->state.authhost.done = TRUE;
358 if (Curl_http_should_fail(conn)) {
359 failf (data, "The requested URL returned error: %d",
360 data->reqdata.keep.httpcode);
361 code = CURLE_HTTP_RETURNED_ERROR;
364 return code;
368 * Curl_http_output_auth() setups the authentication headers for the
369 * host/proxy and the correct authentication
370 * method. conn->data->state.authdone is set to TRUE when authentication is
371 * done.
373 * @param conn all information about the current connection
374 * @param request pointer to the request keyword
375 * @param path pointer to the requested path
376 * @param proxytunnel boolean if this is the request setting up a "proxy
377 * tunnel"
379 * @returns CURLcode
381 static CURLcode
382 Curl_http_output_auth(struct connectdata *conn,
383 char *request,
384 char *path,
385 bool proxytunnel) /* TRUE if this is the request setting
386 up the proxy tunnel */
388 CURLcode result = CURLE_OK;
389 struct SessionHandle *data = conn->data;
390 char *auth=NULL;
391 struct auth *authhost;
392 struct auth *authproxy;
394 curlassert(data);
396 authhost = &data->state.authhost;
397 authproxy = &data->state.authproxy;
399 if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
400 conn->bits.user_passwd)
401 /* continue please */ ;
402 else {
403 authhost->done = TRUE;
404 authproxy->done = TRUE;
405 return CURLE_OK; /* no authentication with no user or password */
408 if(authhost->want && !authhost->picked)
409 /* The app has selected one or more methods, but none has been picked
410 so far by a server round-trip. Then we set the picked one to the
411 want one, and if this is one single bit it'll be used instantly. */
412 authhost->picked = authhost->want;
414 if(authproxy->want && !authproxy->picked)
415 /* The app has selected one or more methods, but none has been picked so
416 far by a proxy round-trip. Then we set the picked one to the want one,
417 and if this is one single bit it'll be used instantly. */
418 authproxy->picked = authproxy->want;
420 /* Send proxy authentication header if needed */
421 if (conn->bits.httpproxy &&
422 (conn->bits.tunnel_proxy == proxytunnel)) {
423 #ifdef USE_NTLM
424 if(authproxy->picked == CURLAUTH_NTLM) {
425 auth=(char *)"NTLM";
426 result = Curl_output_ntlm(conn, TRUE);
427 if(result)
428 return result;
430 else
431 #endif
432 if(authproxy->picked == CURLAUTH_BASIC) {
433 /* Basic */
434 if(conn->bits.proxy_user_passwd &&
435 !checkheaders(data, "Proxy-authorization:")) {
436 auth=(char *)"Basic";
437 result = Curl_output_basic(conn, TRUE);
438 if(result)
439 return result;
441 /* NOTE: Curl_output_basic() should set 'done' TRUE, as the other auth
442 functions work that way */
443 authproxy->done = TRUE;
445 #ifndef CURL_DISABLE_CRYPTO_AUTH
446 else if(authproxy->picked == CURLAUTH_DIGEST) {
447 auth=(char *)"Digest";
448 result = Curl_output_digest(conn,
449 TRUE, /* proxy */
450 (unsigned char *)request,
451 (unsigned char *)path);
452 if(result)
453 return result;
455 #endif
456 if(auth) {
457 infof(data, "Proxy auth using %s with user '%s'\n",
458 auth, conn->proxyuser?conn->proxyuser:"");
459 authproxy->multi = (bool)(!authproxy->done);
461 else
462 authproxy->multi = FALSE;
464 else
465 /* we have no proxy so let's pretend we're done authenticating
466 with it */
467 authproxy->done = TRUE;
469 /* To prevent the user+password to get sent to other than the original
470 host due to a location-follow, we do some weirdo checks here */
471 if(!data->state.this_is_a_follow ||
472 conn->bits.netrc ||
473 !data->state.first_host ||
474 curl_strequal(data->state.first_host, conn->host.name) ||
475 data->set.http_disable_hostname_check_before_authentication) {
477 /* Send web authentication header if needed */
479 auth = NULL;
480 #ifdef HAVE_GSSAPI
481 if((authhost->picked == CURLAUTH_GSSNEGOTIATE) &&
482 data->state.negotiate.context &&
483 !GSS_ERROR(data->state.negotiate.status)) {
484 auth=(char *)"GSS-Negotiate";
485 result = Curl_output_negotiate(conn);
486 if (result)
487 return result;
488 authhost->done = TRUE;
490 else
491 #endif
492 #ifdef USE_NTLM
493 if(authhost->picked == CURLAUTH_NTLM) {
494 auth=(char *)"NTLM";
495 result = Curl_output_ntlm(conn, FALSE);
496 if(result)
497 return result;
499 else
500 #endif
502 #ifndef CURL_DISABLE_CRYPTO_AUTH
503 if(authhost->picked == CURLAUTH_DIGEST) {
504 auth=(char *)"Digest";
505 result = Curl_output_digest(conn,
506 FALSE, /* not a proxy */
507 (unsigned char *)request,
508 (unsigned char *)path);
509 if(result)
510 return result;
511 } else
512 #endif
513 if(authhost->picked == CURLAUTH_BASIC) {
514 if(conn->bits.user_passwd &&
515 !checkheaders(data, "Authorization:")) {
516 auth=(char *)"Basic";
517 result = Curl_output_basic(conn, FALSE);
518 if(result)
519 return result;
521 /* basic is always ready */
522 authhost->done = TRUE;
525 if(auth) {
526 infof(data, "Server auth using %s with user '%s'\n",
527 auth, conn->user);
529 authhost->multi = (bool)(!authhost->done);
531 else
532 authhost->multi = FALSE;
535 else
536 authhost->done = TRUE;
538 return result;
543 * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
544 * headers. They are dealt with both in the transfer.c main loop and in the
545 * proxy CONNECT loop.
548 CURLcode Curl_http_input_auth(struct connectdata *conn,
549 int httpcode,
550 char *header) /* the first non-space */
553 * This resource requires authentication
555 struct SessionHandle *data = conn->data;
557 long *availp;
558 char *start;
559 struct auth *authp;
561 if (httpcode == 407) {
562 start = header+strlen("Proxy-authenticate:");
563 availp = &data->info.proxyauthavail;
564 authp = &data->state.authproxy;
566 else {
567 start = header+strlen("WWW-Authenticate:");
568 availp = &data->info.httpauthavail;
569 authp = &data->state.authhost;
572 /* pass all white spaces */
573 while(*start && ISSPACE(*start))
574 start++;
577 * Here we check if we want the specific single authentication (using ==) and
578 * if we do, we initiate usage of it.
580 * If the provided authentication is wanted as one out of several accepted
581 * types (using &), we OR this authentication type to the authavail
582 * variable.
585 #ifdef HAVE_GSSAPI
586 if (checkprefix("GSS-Negotiate", start) ||
587 checkprefix("Negotiate", start)) {
588 *availp |= CURLAUTH_GSSNEGOTIATE;
589 authp->avail |= CURLAUTH_GSSNEGOTIATE;
590 if(authp->picked == CURLAUTH_GSSNEGOTIATE) {
591 /* if exactly this is wanted, go */
592 int neg = Curl_input_negotiate(conn, start);
593 if (neg == 0) {
594 data->reqdata.newurl = strdup(data->change.url);
595 data->state.authproblem = (data->reqdata.newurl == NULL);
597 else {
598 infof(data, "Authentication problem. Ignoring this.\n");
599 data->state.authproblem = TRUE;
603 else
604 #endif
605 #ifdef USE_NTLM
606 /* NTLM support requires the SSL crypto libs */
607 if(checkprefix("NTLM", start)) {
608 *availp |= CURLAUTH_NTLM;
609 authp->avail |= CURLAUTH_NTLM;
610 if(authp->picked == CURLAUTH_NTLM) {
611 /* NTLM authentication is picked and activated */
612 CURLntlm ntlm =
613 Curl_input_ntlm(conn, (bool)(httpcode == 407), start);
615 if(CURLNTLM_BAD != ntlm)
616 data->state.authproblem = FALSE;
617 else {
618 infof(data, "Authentication problem. Ignoring this.\n");
619 data->state.authproblem = TRUE;
623 else
624 #endif
625 #ifndef CURL_DISABLE_CRYPTO_AUTH
626 if(checkprefix("Digest", start)) {
627 if((authp->avail & CURLAUTH_DIGEST) != 0) {
628 infof(data, "Ignoring duplicate digest auth header.\n");
630 else {
631 CURLdigest dig;
632 *availp |= CURLAUTH_DIGEST;
633 authp->avail |= CURLAUTH_DIGEST;
635 /* We call this function on input Digest headers even if Digest
636 * authentication isn't activated yet, as we need to store the
637 * incoming data from this header in case we are gonna use Digest. */
638 dig = Curl_input_digest(conn, (bool)(httpcode == 407), start);
640 if(CURLDIGEST_FINE != dig) {
641 infof(data, "Authentication problem. Ignoring this.\n");
642 data->state.authproblem = TRUE;
646 else
647 #endif
648 if(checkprefix("Basic", start)) {
649 *availp |= CURLAUTH_BASIC;
650 authp->avail |= CURLAUTH_BASIC;
651 if(authp->picked == CURLAUTH_BASIC) {
652 /* We asked for Basic authentication but got a 40X back
653 anyway, which basicly means our name+password isn't
654 valid. */
655 authp->avail = CURLAUTH_NONE;
656 infof(data, "Authentication problem. Ignoring this.\n");
657 data->state.authproblem = TRUE;
661 return CURLE_OK;
665 * Curl_http_should_fail() determines whether an HTTP response has gotten us
666 * into an error state or not.
668 * @param conn all information about the current connection
670 * @retval 0 communications should continue
672 * @retval 1 communications should not continue
674 int Curl_http_should_fail(struct connectdata *conn)
676 struct SessionHandle *data;
677 struct Curl_transfer_keeper *k;
679 curlassert(conn);
680 data = conn->data;
681 curlassert(data);
684 ** For readability
686 k = &data->reqdata.keep;
689 ** If we haven't been asked to fail on error,
690 ** don't fail.
692 if (!data->set.http_fail_on_error)
693 return 0;
696 ** Any code < 400 is never terminal.
698 if (k->httpcode < 400)
699 return 0;
701 if (data->reqdata.resume_from &&
702 (data->set.httpreq==HTTPREQ_GET) &&
703 (k->httpcode == 416)) {
704 /* "Requested Range Not Satisfiable", just proceed and
705 pretend this is no error */
706 return 0;
710 ** Any code >= 400 that's not 401 or 407 is always
711 ** a terminal error
713 if ((k->httpcode != 401) &&
714 (k->httpcode != 407))
715 return 1;
718 ** All we have left to deal with is 401 and 407
720 curlassert((k->httpcode == 401) || (k->httpcode == 407));
723 ** Examine the current authentication state to see if this
724 ** is an error. The idea is for this function to get
725 ** called after processing all the headers in a response
726 ** message. So, if we've been to asked to authenticate a
727 ** particular stage, and we've done it, we're OK. But, if
728 ** we're already completely authenticated, it's not OK to
729 ** get another 401 or 407.
731 ** It is possible for authentication to go stale such that
732 ** the client needs to reauthenticate. Once that info is
733 ** available, use it here.
735 #if 0 /* set to 1 when debugging this functionality */
736 infof(data,"%s: authstage = %d\n",__FUNCTION__,data->state.authstage);
737 infof(data,"%s: authwant = 0x%08x\n",__FUNCTION__,data->state.authwant);
738 infof(data,"%s: authavail = 0x%08x\n",__FUNCTION__,data->state.authavail);
739 infof(data,"%s: httpcode = %d\n",__FUNCTION__,k->httpcode);
740 infof(data,"%s: authdone = %d\n",__FUNCTION__,data->state.authdone);
741 infof(data,"%s: newurl = %s\n",__FUNCTION__,data->reqdata.newurl ? data->reqdata.newurl : "(null)");
742 infof(data,"%s: authproblem = %d\n",__FUNCTION__,data->state.authproblem);
743 #endif
746 ** Either we're not authenticating, or we're supposed to
747 ** be authenticating something else. This is an error.
749 if((k->httpcode == 401) && !conn->bits.user_passwd)
750 return TRUE;
751 if((k->httpcode == 407) && !conn->bits.proxy_user_passwd)
752 return TRUE;
754 return data->state.authproblem;
758 * readmoredata() is a "fread() emulation" to provide POST and/or request
759 * data. It is used when a huge POST is to be made and the entire chunk wasn't
760 * sent in the first send(). This function will then be called from the
761 * transfer.c loop when more data is to be sent to the peer.
763 * Returns the amount of bytes it filled the buffer with.
765 static size_t readmoredata(char *buffer,
766 size_t size,
767 size_t nitems,
768 void *userp)
770 struct connectdata *conn = (struct connectdata *)userp;
771 struct HTTP *http = conn->data->reqdata.proto.http;
772 size_t fullsize = size * nitems;
774 if(0 == http->postsize)
775 /* nothing to return */
776 return 0;
778 /* make sure that a HTTP request is never sent away chunked! */
779 conn->bits.forbidchunk = (bool)(http->sending == HTTPSEND_REQUEST);
781 if(http->postsize <= (curl_off_t)fullsize) {
782 memcpy(buffer, http->postdata, (size_t)http->postsize);
783 fullsize = (size_t)http->postsize;
785 if(http->backup.postsize) {
786 /* move backup data into focus and continue on that */
787 http->postdata = http->backup.postdata;
788 http->postsize = http->backup.postsize;
789 conn->fread = http->backup.fread;
790 conn->fread_in = http->backup.fread_in;
792 http->sending++; /* move one step up */
794 http->backup.postsize=0;
796 else
797 http->postsize = 0;
799 return fullsize;
802 memcpy(buffer, http->postdata, fullsize);
803 http->postdata += fullsize;
804 http->postsize -= fullsize;
806 return fullsize;
809 /* ------------------------------------------------------------------------- */
811 * The add_buffer series of functions are used to build one large memory chunk
812 * from repeated function invokes. Used so that the entire HTTP request can
813 * be sent in one go.
816 struct send_buffer {
817 char *buffer;
818 size_t size_max;
819 size_t size_used;
821 typedef struct send_buffer send_buffer;
823 static CURLcode add_custom_headers(struct connectdata *conn,
824 send_buffer *req_buffer);
825 static CURLcode
826 add_buffer(send_buffer *in, const void *inptr, size_t size);
829 * add_buffer_init() sets up and returns a fine buffer struct
831 static
832 send_buffer *add_buffer_init(void)
834 send_buffer *blonk;
835 blonk=(send_buffer *)malloc(sizeof(send_buffer));
836 if(blonk) {
837 memset(blonk, 0, sizeof(send_buffer));
838 return blonk;
840 return NULL; /* failed, go home */
844 * add_buffer_send() sends a header buffer and frees all associated memory.
845 * Body data may be appended to the header data if desired.
847 * Returns CURLcode
849 static
850 CURLcode add_buffer_send(send_buffer *in,
851 struct connectdata *conn,
852 long *bytes_written, /* add the number of sent
853 bytes to this counter */
854 size_t included_body_bytes, /* how much of the buffer
855 contains body data (for log tracing) */
856 int socketindex)
859 ssize_t amount;
860 CURLcode res;
861 char *ptr;
862 size_t size;
863 struct HTTP *http = conn->data->reqdata.proto.http;
864 size_t sendsize;
865 curl_socket_t sockfd;
867 curlassert(socketindex <= SECONDARYSOCKET);
869 sockfd = conn->sock[socketindex];
871 /* The looping below is required since we use non-blocking sockets, but due
872 to the circumstances we will just loop and try again and again etc */
874 ptr = in->buffer;
875 size = in->size_used;
877 #ifdef CURL_DOES_CONVERSIONS
878 if(size - included_body_bytes > 0) {
879 res = Curl_convert_to_network(conn->data, ptr, size - included_body_bytes);
880 /* Curl_convert_to_network calls failf if unsuccessful */
881 if(res != CURLE_OK) {
882 /* conversion failed, free memory and return to the caller */
883 if(in->buffer)
884 free(in->buffer);
885 free(in);
886 return res;
889 #endif /* CURL_DOES_CONVERSIONS */
891 if(conn->protocol & PROT_HTTPS) {
892 /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
893 when we speak HTTPS, as if only a fraction of it is sent now, this data
894 needs to fit into the normal read-callback buffer later on and that
895 buffer is using this size.
898 sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:size;
900 /* OpenSSL is very picky and we must send the SAME buffer pointer to the
901 library when we attempt to re-send this buffer. Sending the same data
902 is not enough, we must use the exact same address. For this reason, we
903 must copy the data to the uploadbuffer first, since that is the buffer
904 we will be using if this send is retried later.
906 memcpy(conn->data->state.uploadbuffer, ptr, sendsize);
907 ptr = conn->data->state.uploadbuffer;
909 else
910 sendsize = size;
912 res = Curl_write(conn, sockfd, ptr, sendsize, &amount);
914 if(CURLE_OK == res) {
916 if(conn->data->set.verbose) {
917 /* this data _may_ contain binary stuff */
918 Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr,
919 (size_t)(amount-included_body_bytes), conn);
920 if (included_body_bytes)
921 Curl_debug(conn->data, CURLINFO_DATA_OUT,
922 ptr+amount-included_body_bytes,
923 (size_t)included_body_bytes, conn);
926 *bytes_written += amount;
928 if(http) {
929 if((size_t)amount != size) {
930 /* The whole request could not be sent in one system call. We must
931 queue it up and send it later when we get the chance. We must not
932 loop here and wait until it might work again. */
934 size -= amount;
936 ptr = in->buffer + amount;
938 /* backup the currently set pointers */
939 http->backup.fread = conn->fread;
940 http->backup.fread_in = conn->fread_in;
941 http->backup.postdata = http->postdata;
942 http->backup.postsize = http->postsize;
944 /* set the new pointers for the request-sending */
945 conn->fread = (curl_read_callback)readmoredata;
946 conn->fread_in = (void *)conn;
947 http->postdata = ptr;
948 http->postsize = (curl_off_t)size;
950 http->send_buffer = in;
951 http->sending = HTTPSEND_REQUEST;
953 return CURLE_OK;
955 http->sending = HTTPSEND_BODY;
956 /* the full buffer was sent, clean up and return */
958 else {
959 if((size_t)amount != size)
960 /* We have no continue-send mechanism now, fail. This can only happen
961 when this function is used from the CONNECT sending function. We
962 currently (stupidly) assume that the whole request is always sent
963 away in the first single chunk.
965 This needs FIXing.
967 return CURLE_SEND_ERROR;
968 else
969 conn->writechannel_inuse = FALSE;
972 if(in->buffer)
973 free(in->buffer);
974 free(in);
976 return res;
981 * add_bufferf() add the formatted input to the buffer.
983 static
984 CURLcode add_bufferf(send_buffer *in, const char *fmt, ...)
986 char *s;
987 va_list ap;
988 va_start(ap, fmt);
989 s = vaprintf(fmt, ap); /* this allocs a new string to append */
990 va_end(ap);
992 if(s) {
993 CURLcode result = add_buffer(in, s, strlen(s));
994 free(s);
995 if(CURLE_OK == result)
996 return CURLE_OK;
998 /* If we failed, we cleanup the whole buffer and return error */
999 if(in->buffer)
1000 free(in->buffer);
1001 free(in);
1002 return CURLE_OUT_OF_MEMORY;
1006 * add_buffer() appends a memory chunk to the existing buffer
1008 static
1009 CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size)
1011 char *new_rb;
1012 size_t new_size;
1014 if(!in->buffer ||
1015 ((in->size_used + size) > (in->size_max - 1))) {
1016 new_size = (in->size_used+size)*2;
1017 if(in->buffer)
1018 /* we have a buffer, enlarge the existing one */
1019 new_rb = (char *)realloc(in->buffer, new_size);
1020 else
1021 /* create a new buffer */
1022 new_rb = (char *)malloc(new_size);
1024 if(!new_rb)
1025 return CURLE_OUT_OF_MEMORY;
1027 in->buffer = new_rb;
1028 in->size_max = new_size;
1030 memcpy(&in->buffer[in->size_used], inptr, size);
1032 in->size_used += size;
1034 return CURLE_OK;
1037 /* end of the add_buffer functions */
1038 /* ------------------------------------------------------------------------- */
1041 * Curl_compareheader()
1043 * Returns TRUE if 'headerline' contains the 'header' with given 'content'.
1044 * Pass headers WITH the colon.
1046 bool
1047 Curl_compareheader(char *headerline, /* line to check */
1048 const char *header, /* header keyword _with_ colon */
1049 const char *content) /* content string to find */
1051 /* RFC2616, section 4.2 says: "Each header field consists of a name followed
1052 * by a colon (":") and the field value. Field names are case-insensitive.
1053 * The field value MAY be preceded by any amount of LWS, though a single SP
1054 * is preferred." */
1056 size_t hlen = strlen(header);
1057 size_t clen;
1058 size_t len;
1059 char *start;
1060 char *end;
1062 if(!strnequal(headerline, header, hlen))
1063 return FALSE; /* doesn't start with header */
1065 /* pass the header */
1066 start = &headerline[hlen];
1068 /* pass all white spaces */
1069 while(*start && ISSPACE(*start))
1070 start++;
1072 /* find the end of the header line */
1073 end = strchr(start, '\r'); /* lines end with CRLF */
1074 if(!end) {
1075 /* in case there's a non-standard compliant line here */
1076 end = strchr(start, '\n');
1078 if(!end)
1079 /* hm, there's no line ending here, use the zero byte! */
1080 end = strchr(start, '\0');
1083 len = end-start; /* length of the content part of the input line */
1084 clen = strlen(content); /* length of the word to find */
1086 /* find the content string in the rest of the line */
1087 for(;len>=clen;len--, start++) {
1088 if(strnequal(start, content, clen))
1089 return TRUE; /* match! */
1092 return FALSE; /* no match */
1096 * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
1097 * function will issue the necessary commands to get a seamless tunnel through
1098 * this proxy. After that, the socket can be used just as a normal socket.
1100 * This badly needs to be rewritten. CONNECT should be sent and dealt with
1101 * like any ordinary HTTP request, and not specially crafted like this. This
1102 * function only remains here like this for now since the rewrite is a bit too
1103 * much work to do at the moment.
1105 * This function is BLOCKING which is nasty for all multi interface using apps.
1108 CURLcode Curl_proxyCONNECT(struct connectdata *conn,
1109 int sockindex,
1110 char *hostname,
1111 int remote_port)
1113 int subversion=0;
1114 struct SessionHandle *data=conn->data;
1115 struct Curl_transfer_keeper *k = &data->reqdata.keep;
1116 CURLcode result;
1117 int res;
1118 size_t nread; /* total size read */
1119 int perline; /* count bytes per line */
1120 int keepon=TRUE;
1121 ssize_t gotbytes;
1122 char *ptr;
1123 long timeout =
1124 data->set.timeout?data->set.timeout:3600; /* in seconds */
1125 char *line_start;
1126 char *host_port;
1127 curl_socket_t tunnelsocket = conn->sock[sockindex];
1128 send_buffer *req_buffer;
1129 curl_off_t cl=0;
1130 bool closeConnection = FALSE;
1132 #define SELECT_OK 0
1133 #define SELECT_ERROR 1
1134 #define SELECT_TIMEOUT 2
1135 int error = SELECT_OK;
1137 infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
1138 conn->bits.proxy_connect_closed = FALSE;
1140 do {
1141 if(data->reqdata.newurl) {
1142 /* This only happens if we've looped here due to authentication reasons,
1143 and we don't really use the newly cloned URL here then. Just free()
1144 it. */
1145 free(data->reqdata.newurl);
1146 data->reqdata.newurl = NULL;
1149 /* initialize a dynamic send-buffer */
1150 req_buffer = add_buffer_init();
1152 if(!req_buffer)
1153 return CURLE_OUT_OF_MEMORY;
1155 host_port = aprintf("%s:%d", hostname, remote_port);
1156 if(!host_port)
1157 return CURLE_OUT_OF_MEMORY;
1159 /* Setup the proxy-authorization header, if any */
1160 result = Curl_http_output_auth(conn, (char *)"CONNECT", host_port, TRUE);
1162 if(CURLE_OK == result) {
1163 char *host=(char *)"";
1164 const char *proxyconn="";
1165 const char *useragent="";
1167 if(!checkheaders(data, "Host:")) {
1168 host = aprintf("Host: %s\r\n", host_port);
1169 if(!host)
1170 result = CURLE_OUT_OF_MEMORY;
1172 if(!checkheaders(data, "Proxy-Connection:"))
1173 proxyconn = "Proxy-Connection: Keep-Alive\r\n";
1175 if(!checkheaders(data, "User-Agent:") && data->set.useragent)
1176 useragent = conn->allocptr.uagent;
1178 if(CURLE_OK == result) {
1179 /* Send the connect request to the proxy */
1180 /* BLOCKING */
1181 result =
1182 add_bufferf(req_buffer,
1183 "CONNECT %s:%d HTTP/1.0\r\n"
1184 "%s" /* Host: */
1185 "%s" /* Proxy-Authorization */
1186 "%s" /* User-Agent */
1187 "%s", /* Proxy-Connection */
1188 hostname, remote_port,
1189 host,
1190 conn->allocptr.proxyuserpwd?
1191 conn->allocptr.proxyuserpwd:"",
1192 useragent,
1193 proxyconn);
1195 if(CURLE_OK == result)
1196 result = add_custom_headers(conn, req_buffer);
1198 if(host && *host)
1199 free(host);
1201 if(CURLE_OK == result)
1202 /* CRLF terminate the request */
1203 result = add_bufferf(req_buffer, "\r\n");
1205 if(CURLE_OK == result)
1206 /* Now send off the request */
1207 result = add_buffer_send(req_buffer, conn,
1208 &data->info.request_size, 0, sockindex);
1210 if(result)
1211 failf(data, "Failed sending CONNECT to proxy");
1213 free(host_port);
1214 if(result)
1215 return result;
1217 ptr=data->state.buffer;
1218 line_start = ptr;
1220 nread=0;
1221 perline=0;
1222 keepon=TRUE;
1224 while((nread<BUFSIZE) && (keepon && !error)) {
1226 /* if timeout is requested, find out how much remaining time we have */
1227 long check = timeout - /* timeout time */
1228 Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
1229 if(check <=0 ) {
1230 failf(data, "Proxy CONNECT aborted due to timeout");
1231 error = SELECT_TIMEOUT; /* already too little time */
1232 break;
1235 /* timeout each second and check the timeout */
1236 switch (Curl_select(tunnelsocket, CURL_SOCKET_BAD, 1000)) {
1237 case -1: /* select() error, stop reading */
1238 error = SELECT_ERROR;
1239 failf(data, "Proxy CONNECT aborted due to select() error");
1240 break;
1241 case 0: /* timeout */
1242 break;
1243 default:
1244 res = Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes);
1245 if(res< 0)
1246 /* EWOULDBLOCK */
1247 continue; /* go loop yourself */
1248 else if(res)
1249 keepon = FALSE;
1250 else if(gotbytes <= 0) {
1251 keepon = FALSE;
1252 error = SELECT_ERROR;
1253 failf(data, "Proxy CONNECT aborted");
1255 else {
1257 * We got a whole chunk of data, which can be anything from one byte
1258 * to a set of lines and possibly just a piece of the last line.
1260 int i;
1262 nread += gotbytes;
1264 if(keepon > TRUE) {
1265 /* This means we are currently ignoring a response-body, so we
1266 simply count down our counter and make sure to break out of the
1267 loop when we're done! */
1268 cl -= gotbytes;
1269 if(cl<=0) {
1270 keepon = FALSE;
1271 break;
1274 else
1275 for(i = 0; i < gotbytes; ptr++, i++) {
1276 perline++; /* amount of bytes in this line so far */
1277 if(*ptr=='\n') {
1278 char letter;
1279 int writetype;
1281 /* output debug if that is requested */
1282 if(data->set.verbose)
1283 Curl_debug(data, CURLINFO_HEADER_IN,
1284 line_start, (size_t)perline, conn);
1286 /* send the header to the callback */
1287 writetype = CLIENTWRITE_HEADER;
1288 if(data->set.include_header)
1289 writetype |= CLIENTWRITE_BODY;
1291 result = Curl_client_write(conn, writetype, line_start, perline);
1292 if(result)
1293 return result;
1295 /* Newlines are CRLF, so the CR is ignored as the line isn't
1296 really terminated until the LF comes. Treat a following CR
1297 as end-of-headers as well.*/
1299 if(('\r' == line_start[0]) ||
1300 ('\n' == line_start[0])) {
1301 /* end of response-headers from the proxy */
1302 if(cl && (407 == k->httpcode) && !data->state.authproblem) {
1303 /* If we get a 407 response code with content length when we
1304 * have no auth problem, we must ignore the whole
1305 * response-body */
1306 keepon = 2;
1307 infof(data, "Ignore %" FORMAT_OFF_T
1308 " bytes of response-body\n", cl);
1309 cl -= (gotbytes - i);/* remove the remaining chunk of what
1310 we already read */
1311 if(cl<=0)
1312 /* if the whole thing was already read, we are done! */
1313 keepon=FALSE;
1315 else
1316 keepon = FALSE;
1317 break; /* breaks out of for-loop, not switch() */
1320 /* keep a backup of the position we are about to blank */
1321 letter = line_start[perline];
1322 line_start[perline]=0; /* zero terminate the buffer */
1323 if((checkprefix("WWW-Authenticate:", line_start) &&
1324 (401 == k->httpcode)) ||
1325 (checkprefix("Proxy-authenticate:", line_start) &&
1326 (407 == k->httpcode))) {
1327 result = Curl_http_input_auth(conn, k->httpcode, line_start);
1328 if(result)
1329 return result;
1331 else if(checkprefix("Content-Length:", line_start)) {
1332 cl = curlx_strtoofft(line_start + strlen("Content-Length:"),
1333 NULL, 10);
1335 else if(Curl_compareheader(line_start,
1336 "Connection:", "close"))
1337 closeConnection = TRUE;
1338 else if(2 == sscanf(line_start, "HTTP/1.%d %d",
1339 &subversion,
1340 &k->httpcode)) {
1341 /* store the HTTP code from the proxy */
1342 data->info.httpproxycode = k->httpcode;
1344 /* put back the letter we blanked out before */
1345 line_start[perline]= letter;
1347 perline=0; /* line starts over here */
1348 line_start = ptr+1; /* this skips the zero byte we wrote */
1352 break;
1353 } /* switch */
1354 } /* while there's buffer left and loop is requested */
1356 if(error)
1357 return CURLE_RECV_ERROR;
1359 if(data->info.httpproxycode != 200)
1360 /* Deal with the possibly already received authenticate
1361 headers. 'newurl' is set to a new URL if we must loop. */
1362 Curl_http_auth_act(conn);
1364 if (closeConnection && data->reqdata.newurl) {
1365 /* Connection closed by server. Don't use it anymore */
1366 sclose(conn->sock[sockindex]);
1367 conn->sock[sockindex] = CURL_SOCKET_BAD;
1368 break;
1370 } while(data->reqdata.newurl);
1372 if(200 != k->httpcode) {
1373 failf(data, "Received HTTP code %d from proxy after CONNECT",
1374 k->httpcode);
1376 if (closeConnection && data->reqdata.newurl)
1377 conn->bits.proxy_connect_closed = TRUE;
1379 return CURLE_RECV_ERROR;
1382 /* If a proxy-authorization header was used for the proxy, then we should
1383 make sure that it isn't accidentally used for the document request
1384 after we've connected. So let's free and clear it here. */
1385 Curl_safefree(conn->allocptr.proxyuserpwd);
1386 conn->allocptr.proxyuserpwd = NULL;
1388 data->state.authproxy.done = TRUE;
1390 infof (data, "Proxy replied OK to CONNECT request\n");
1391 return CURLE_OK;
1395 * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
1396 * the generic Curl_connect().
1398 CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
1400 struct SessionHandle *data;
1401 CURLcode result;
1403 data=conn->data;
1405 /* If we are not using a proxy and we want a secure connection, perform SSL
1406 * initialization & connection now. If using a proxy with https, then we
1407 * must tell the proxy to CONNECT to the host we want to talk to. Only
1408 * after the connect has occurred, can we start talking SSL
1411 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1413 /* either SSL over proxy, or explicitly asked for */
1414 result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
1415 conn->host.name,
1416 conn->remote_port);
1417 if(CURLE_OK != result)
1418 return result;
1421 if(!data->state.this_is_a_follow) {
1422 /* this is not a followed location, get the original host name */
1423 if (data->state.first_host)
1424 /* Free to avoid leaking memory on multiple requests*/
1425 free(data->state.first_host);
1427 data->state.first_host = strdup(conn->host.name);
1428 if(!data->state.first_host)
1429 return CURLE_OUT_OF_MEMORY;
1432 if(conn->protocol & PROT_HTTPS) {
1433 /* perform SSL initialization */
1434 if(data->state.used_interface == Curl_if_multi) {
1435 result = Curl_https_connecting(conn, done);
1436 if(result)
1437 return result;
1439 else {
1440 /* BLOCKING */
1441 result = Curl_ssl_connect(conn, FIRSTSOCKET);
1442 if(result)
1443 return result;
1444 *done = TRUE;
1447 else {
1448 *done = TRUE;
1451 return CURLE_OK;
1454 CURLcode Curl_https_connecting(struct connectdata *conn, bool *done)
1456 CURLcode result;
1457 curlassert(conn->protocol & PROT_HTTPS);
1459 /* perform SSL initialization for this socket */
1460 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done);
1461 if(result)
1462 return result;
1464 return CURLE_OK;
1467 #ifdef USE_SSLEAY
1468 /* This function is OpenSSL-specific. It should be made to query the generic
1469 SSL layer instead. */
1470 int Curl_https_getsock(struct connectdata *conn,
1471 curl_socket_t *socks,
1472 int numsocks)
1474 if (conn->protocol & PROT_HTTPS) {
1475 struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
1477 if(!numsocks)
1478 return GETSOCK_BLANK;
1480 if (connssl->connecting_state == ssl_connect_2_writing) {
1481 /* write mode */
1482 socks[0] = conn->sock[FIRSTSOCKET];
1483 return GETSOCK_WRITESOCK(0);
1485 else if (connssl->connecting_state == ssl_connect_2_reading) {
1486 /* read mode */
1487 socks[0] = conn->sock[FIRSTSOCKET];
1488 return GETSOCK_READSOCK(0);
1491 return CURLE_OK;
1493 #else
1494 #ifdef USE_GNUTLS
1495 int Curl_https_getsock(struct connectdata *conn,
1496 curl_socket_t *socks,
1497 int numsocks)
1499 (void)conn;
1500 (void)socks;
1501 (void)numsocks;
1502 return GETSOCK_BLANK;
1504 #endif
1505 #endif
1508 * Curl_http_done() gets called from Curl_done() after a single HTTP request
1509 * has been performed.
1512 CURLcode Curl_http_done(struct connectdata *conn,
1513 CURLcode status, bool premature)
1515 struct SessionHandle *data = conn->data;
1516 struct HTTP *http =data->reqdata.proto.http;
1517 struct Curl_transfer_keeper *k = &data->reqdata.keep;
1518 (void)premature; /* not used */
1520 /* set the proper values (possibly modified on POST) */
1521 conn->fread = data->set.fread; /* restore */
1522 conn->fread_in = data->set.in; /* restore */
1524 if (http == NULL)
1525 return CURLE_OK;
1527 if(http->send_buffer) {
1528 send_buffer *buff = http->send_buffer;
1530 free(buff->buffer);
1531 free(buff);
1532 http->send_buffer = NULL; /* clear the pointer */
1535 if(HTTPREQ_POST_FORM == data->set.httpreq) {
1536 k->bytecount = http->readbytecount + http->writebytecount;
1538 Curl_formclean(&http->sendit); /* Now free that whole lot */
1539 if(http->form.fp) {
1540 /* a file being uploaded was left opened, close it! */
1541 fclose(http->form.fp);
1542 http->form.fp = NULL;
1545 else if(HTTPREQ_PUT == data->set.httpreq)
1546 k->bytecount = http->readbytecount + http->writebytecount;
1548 if (status != CURLE_OK)
1549 return (status);
1551 if(!conn->bits.retry &&
1552 ((http->readbytecount +
1553 conn->headerbytecount -
1554 conn->deductheadercount)) <= 0) {
1555 /* If this connection isn't simply closed to be retried, AND nothing was
1556 read from the HTTP server (that counts), this can't be right so we
1557 return an error here */
1558 failf(data, "Empty reply from server");
1559 return CURLE_GOT_NOTHING;
1562 return CURLE_OK;
1565 /* check and possibly add an Expect: header */
1566 static CURLcode expect100(struct SessionHandle *data,
1567 send_buffer *req_buffer)
1569 CURLcode result = CURLE_OK;
1570 data->state.expect100header = FALSE; /* default to false unless it is set
1571 to TRUE below */
1572 if((data->set.httpversion != CURL_HTTP_VERSION_1_0) &&
1573 !checkheaders(data, "Expect:")) {
1574 /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect:
1575 100-continue to the headers which actually speeds up post
1576 operations (as there is one packet coming back from the web
1577 server) */
1578 result = add_bufferf(req_buffer,
1579 "Expect: 100-continue\r\n");
1580 if(result == CURLE_OK)
1581 data->state.expect100header = TRUE;
1583 return result;
1586 static CURLcode add_custom_headers(struct connectdata *conn,
1587 send_buffer *req_buffer)
1589 CURLcode result = CURLE_OK;
1590 char *ptr;
1591 struct curl_slist *headers=conn->data->set.headers;
1593 while(headers) {
1594 ptr = strchr(headers->data, ':');
1595 if(ptr) {
1596 /* we require a colon for this to be a true header */
1598 ptr++; /* pass the colon */
1599 while(*ptr && ISSPACE(*ptr))
1600 ptr++;
1602 if(*ptr) {
1603 /* only send this if the contents was non-blank */
1605 if(conn->allocptr.host &&
1606 /* a Host: header was sent already, don't pass on any custom Host:
1607 header as that will produce *two* in the same request! */
1608 curl_strnequal("Host:", headers->data, 5))
1610 else if(conn->data->set.httpreq == HTTPREQ_POST_FORM &&
1611 /* this header (extended by formdata.c) is sent later */
1612 curl_strnequal("Content-Type:", headers->data,
1613 strlen("Content-Type:")))
1615 else {
1616 result = add_bufferf(req_buffer, "%s\r\n", headers->data);
1617 if(result)
1618 return result;
1622 headers = headers->next;
1624 return result;
1628 * Curl_http() gets called from the generic Curl_do() function when a HTTP
1629 * request is to be performed. This creates and sends a properly constructed
1630 * HTTP request.
1632 CURLcode Curl_http(struct connectdata *conn, bool *done)
1634 struct SessionHandle *data=conn->data;
1635 char *buf = data->state.buffer; /* this is a short cut to the buffer */
1636 CURLcode result=CURLE_OK;
1637 struct HTTP *http;
1638 char *ppath = data->reqdata.path;
1639 char *host = conn->host.name;
1640 const char *te = ""; /* transfer-encoding */
1641 char *ptr;
1642 char *request;
1643 Curl_HttpReq httpreq = data->set.httpreq;
1644 char *addcookies = NULL;
1645 curl_off_t included_body = 0;
1647 /* Always consider the DO phase done after this function call, even if there
1648 may be parts of the request that is not yet sent, since we can deal with
1649 the rest of the request in the PERFORM phase. */
1650 *done = TRUE;
1652 if(!data->reqdata.proto.http) {
1653 /* Only allocate this struct if we don't already have it! */
1655 http = (struct HTTP *)malloc(sizeof(struct HTTP));
1656 if(!http)
1657 return CURLE_OUT_OF_MEMORY;
1658 memset(http, 0, sizeof(struct HTTP));
1659 data->reqdata.proto.http = http;
1661 else
1662 http = data->reqdata.proto.http;
1664 /* We default to persistent connections */
1665 conn->bits.close = FALSE;
1667 if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) &&
1668 data->set.upload) {
1669 httpreq = HTTPREQ_PUT;
1672 /* Now set the 'request' pointer to the proper request string */
1673 if(data->set.customrequest)
1674 request = data->set.customrequest;
1675 else {
1676 if(conn->bits.no_body)
1677 request = (char *)"HEAD";
1678 else {
1679 curlassert((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST));
1680 switch(httpreq) {
1681 case HTTPREQ_POST:
1682 case HTTPREQ_POST_FORM:
1683 request = (char *)"POST";
1684 break;
1685 case HTTPREQ_PUT:
1686 request = (char *)"PUT";
1687 break;
1688 default: /* this should never happen */
1689 case HTTPREQ_GET:
1690 request = (char *)"GET";
1691 break;
1692 case HTTPREQ_HEAD:
1693 request = (char *)"HEAD";
1694 break;
1699 /* The User-Agent string might have been allocated in url.c already, because
1700 it might have been used in the proxy connect, but if we have got a header
1701 with the user-agent string specified, we erase the previously made string
1702 here. */
1703 if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
1704 free(conn->allocptr.uagent);
1705 conn->allocptr.uagent=NULL;
1708 /* setup the authentication headers */
1709 result = Curl_http_output_auth(conn, request, ppath, FALSE);
1710 if(result)
1711 return result;
1713 if((data->state.authhost.multi || data->state.authproxy.multi) &&
1714 (httpreq != HTTPREQ_GET) &&
1715 (httpreq != HTTPREQ_HEAD)) {
1716 /* Auth is required and we are not authenticated yet. Make a PUT or POST
1717 with content-length zero as a "probe". */
1718 conn->bits.authneg = TRUE;
1720 else
1721 conn->bits.authneg = FALSE;
1723 Curl_safefree(conn->allocptr.ref);
1724 if(data->change.referer && !checkheaders(data, "Referer:"))
1725 conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
1726 else
1727 conn->allocptr.ref = NULL;
1729 if(data->set.cookie && !checkheaders(data, "Cookie:"))
1730 addcookies = data->set.cookie;
1732 if(!checkheaders(data, "Accept-Encoding:") &&
1733 data->set.encoding) {
1734 Curl_safefree(conn->allocptr.accept_encoding);
1735 conn->allocptr.accept_encoding =
1736 aprintf("Accept-Encoding: %s\r\n", data->set.encoding);
1737 if(!conn->allocptr.accept_encoding)
1738 return CURLE_OUT_OF_MEMORY;
1741 ptr = checkheaders(data, "Transfer-Encoding:");
1742 if(ptr) {
1743 /* Some kind of TE is requested, check if 'chunked' is chosen */
1744 conn->bits.upload_chunky =
1745 Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
1747 else {
1748 if (httpreq == HTTPREQ_GET)
1749 conn->bits.upload_chunky = FALSE;
1750 if(conn->bits.upload_chunky)
1751 te = "Transfer-Encoding: chunked\r\n";
1754 Curl_safefree(conn->allocptr.host);
1756 ptr = checkheaders(data, "Host:");
1757 if(ptr && (!data->state.this_is_a_follow ||
1758 curl_strequal(data->state.first_host, conn->host.name))) {
1759 #if !defined(CURL_DISABLE_COOKIES)
1760 /* If we have a given custom Host: header, we extract the host name in
1761 order to possibly use it for cookie reasons later on. We only allow the
1762 custom Host: header if this is NOT a redirect, as setting Host: in the
1763 redirected request is being out on thin ice. Except if the host name
1764 is the same as the first one! */
1765 char *start = ptr+strlen("Host:");
1766 while(*start && ISSPACE(*start ))
1767 start++;
1768 ptr = start; /* start host-scanning here */
1770 /* scan through the string to find the end (space or colon) */
1771 while(*ptr && !ISSPACE(*ptr) && !(':'==*ptr))
1772 ptr++;
1774 if(ptr != start) {
1775 size_t len=ptr-start;
1776 Curl_safefree(conn->allocptr.cookiehost);
1777 conn->allocptr.cookiehost = malloc(len+1);
1778 if(!conn->allocptr.cookiehost)
1779 return CURLE_OUT_OF_MEMORY;
1780 memcpy(conn->allocptr.cookiehost, start, len);
1781 conn->allocptr.cookiehost[len]=0;
1783 #endif
1785 conn->allocptr.host = NULL;
1787 else {
1788 /* When building Host: headers, we must put the host name within
1789 [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
1791 if(((conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTPS)) ||
1792 (!(conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTP)) )
1793 /* If (HTTPS on port 443) OR (non-HTTPS on port 80) then don't include
1794 the port number in the host string */
1795 conn->allocptr.host = aprintf("Host: %s%s%s\r\n",
1796 conn->bits.ipv6_ip?"[":"",
1797 host,
1798 conn->bits.ipv6_ip?"]":"");
1799 else
1800 conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n",
1801 conn->bits.ipv6_ip?"[":"",
1802 host,
1803 conn->bits.ipv6_ip?"]":"",
1804 conn->remote_port);
1806 if(!conn->allocptr.host)
1807 /* without Host: we can't make a nice request */
1808 return CURLE_OUT_OF_MEMORY;
1811 if (conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
1812 /* Using a proxy but does not tunnel through it */
1814 /* The path sent to the proxy is in fact the entire URL. But if the remote
1815 host is a IDN-name, we must make sure that the request we produce only
1816 uses the encoded host name! */
1817 if(conn->host.dispname != conn->host.name) {
1818 char *url = data->change.url;
1819 ptr = strstr(url, conn->host.dispname);
1820 if(ptr) {
1821 /* This is where the display name starts in the URL, now replace this
1822 part with the encoded name. TODO: This method of replacing the host
1823 name is rather crude as I believe there's a slight risk that the
1824 user has entered a user name or password that contain the host name
1825 string. */
1826 size_t currlen = strlen(conn->host.dispname);
1827 size_t newlen = strlen(conn->host.name);
1828 size_t urllen = strlen(url);
1830 char *newurl;
1832 newurl = malloc(urllen + newlen - currlen + 1);
1833 if(newurl) {
1834 /* copy the part before the host name */
1835 memcpy(newurl, url, ptr - url);
1836 /* append the new host name instead of the old */
1837 memcpy(newurl + (ptr - url), conn->host.name, newlen);
1838 /* append the piece after the host name */
1839 memcpy(newurl + newlen + (ptr - url),
1840 ptr + currlen, /* copy the trailing zero byte too */
1841 urllen - (ptr-url) - currlen + 1);
1842 if(data->change.url_alloc)
1843 free(data->change.url);
1844 data->change.url = newurl;
1845 data->change.url_alloc = TRUE;
1847 else
1848 return CURLE_OUT_OF_MEMORY;
1851 ppath = data->change.url;
1853 if(HTTPREQ_POST_FORM == httpreq) {
1854 /* we must build the whole darned post sequence first, so that we have
1855 a size of the whole shebang before we start to send it */
1856 result = Curl_getFormData(&http->sendit, data->set.httppost,
1857 checkheaders(data, "Content-Type:"),
1858 &http->postsize);
1859 if(CURLE_OK != result) {
1860 /* Curl_getFormData() doesn't use failf() */
1861 failf(data, "failed creating formpost data");
1862 return result;
1867 http->p_pragma =
1868 (!checkheaders(data, "Pragma:") &&
1869 (conn->bits.httpproxy && !conn->bits.tunnel_proxy) )?
1870 "Pragma: no-cache\r\n":NULL;
1872 if(!checkheaders(data, "Accept:"))
1873 http->p_accept = "Accept: */*\r\n";
1875 if(( (HTTPREQ_POST == httpreq) ||
1876 (HTTPREQ_POST_FORM == httpreq) ||
1877 (HTTPREQ_PUT == httpreq) ) &&
1878 data->reqdata.resume_from) {
1879 /**********************************************************************
1880 * Resuming upload in HTTP means that we PUT or POST and that we have
1881 * got a resume_from value set. The resume value has already created
1882 * a Range: header that will be passed along. We need to "fast forward"
1883 * the file the given number of bytes and decrease the assume upload
1884 * file size before we continue this venture in the dark lands of HTTP.
1885 *********************************************************************/
1887 if(data->reqdata.resume_from < 0 ) {
1889 * This is meant to get the size of the present remote-file by itself.
1890 * We don't support this now. Bail out!
1892 data->reqdata.resume_from = 0;
1895 if(data->reqdata.resume_from) {
1896 /* do we still game? */
1897 curl_off_t passed=0;
1899 /* Now, let's read off the proper amount of bytes from the
1900 input. If we knew it was a proper file we could've just
1901 fseek()ed but we only have a stream here */
1902 do {
1903 size_t readthisamountnow = (size_t)(data->reqdata.resume_from - passed);
1904 size_t actuallyread;
1906 if(readthisamountnow > BUFSIZE)
1907 readthisamountnow = BUFSIZE;
1909 actuallyread =
1910 data->set.fread(data->state.buffer, 1, (size_t)readthisamountnow,
1911 data->set.in);
1913 passed += actuallyread;
1914 if(actuallyread != readthisamountnow) {
1915 failf(data, "Could only read %" FORMAT_OFF_T
1916 " bytes from the input",
1917 passed);
1918 return CURLE_READ_ERROR;
1920 } while(passed != data->reqdata.resume_from); /* loop until done */
1922 /* now, decrease the size of the read */
1923 if(data->set.infilesize>0) {
1924 data->set.infilesize -= data->reqdata.resume_from;
1926 if(data->set.infilesize <= 0) {
1927 failf(data, "File already completely uploaded");
1928 return CURLE_PARTIAL_FILE;
1931 /* we've passed, proceed as normal */
1934 if(data->reqdata.use_range) {
1936 * A range is selected. We use different headers whether we're downloading
1937 * or uploading and we always let customized headers override our internal
1938 * ones if any such are specified.
1940 if((httpreq == HTTPREQ_GET) &&
1941 !checkheaders(data, "Range:")) {
1942 /* if a line like this was already allocated, free the previous one */
1943 if(conn->allocptr.rangeline)
1944 free(conn->allocptr.rangeline);
1945 conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", data->reqdata.range);
1947 else if((httpreq != HTTPREQ_GET) &&
1948 !checkheaders(data, "Content-Range:")) {
1950 if(data->reqdata.resume_from) {
1951 /* This is because "resume" was selected */
1952 curl_off_t total_expected_size=
1953 data->reqdata.resume_from + data->set.infilesize;
1954 conn->allocptr.rangeline =
1955 aprintf("Content-Range: bytes %s%" FORMAT_OFF_T
1956 "/%" FORMAT_OFF_T "\r\n",
1957 data->reqdata.range, total_expected_size-1,
1958 total_expected_size);
1960 else {
1961 /* Range was selected and then we just pass the incoming range and
1962 append total size */
1963 conn->allocptr.rangeline =
1964 aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n",
1965 data->reqdata.range, data->set.infilesize);
1971 /* Use 1.1 unless the use specificly asked for 1.0 */
1972 const char *httpstring=
1973 data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1";
1975 send_buffer *req_buffer;
1976 curl_off_t postsize; /* off_t type to be able to hold a large file size */
1978 /* initialize a dynamic send-buffer */
1979 req_buffer = add_buffer_init();
1981 if(!req_buffer)
1982 return CURLE_OUT_OF_MEMORY;
1984 /* add the main request stuff */
1985 result =
1986 add_bufferf(req_buffer,
1987 "%s " /* GET/HEAD/POST/PUT */
1988 "%s HTTP/%s\r\n" /* path + HTTP version */
1989 "%s" /* proxyuserpwd */
1990 "%s" /* userpwd */
1991 "%s" /* range */
1992 "%s" /* user agent */
1993 "%s" /* host */
1994 "%s" /* pragma */
1995 "%s" /* accept */
1996 "%s" /* accept-encoding */
1997 "%s" /* referer */
1998 "%s" /* Proxy-Connection */
1999 "%s",/* transfer-encoding */
2001 request,
2002 ppath,
2003 httpstring,
2004 conn->allocptr.proxyuserpwd?
2005 conn->allocptr.proxyuserpwd:"",
2006 conn->allocptr.userpwd?conn->allocptr.userpwd:"",
2007 (data->reqdata.use_range && conn->allocptr.rangeline)?
2008 conn->allocptr.rangeline:"",
2009 (data->set.useragent && *data->set.useragent && conn->allocptr.uagent)?
2010 conn->allocptr.uagent:"",
2011 (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */
2012 http->p_pragma?http->p_pragma:"",
2013 http->p_accept?http->p_accept:"",
2014 (data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)?
2015 conn->allocptr.accept_encoding:"",
2016 (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: <data> */,
2017 (conn->bits.httpproxy &&
2018 !conn->bits.tunnel_proxy &&
2019 !checkheaders(data, "Proxy-Connection:"))?
2020 "Proxy-Connection: Keep-Alive\r\n":"",
2024 if(result)
2025 return result;
2027 #if !defined(CURL_DISABLE_COOKIES)
2028 if(data->cookies || addcookies) {
2029 struct Cookie *co=NULL; /* no cookies from start */
2030 int count=0;
2032 if(data->cookies) {
2033 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
2034 co = Curl_cookie_getlist(data->cookies,
2035 conn->allocptr.cookiehost?
2036 conn->allocptr.cookiehost:host, data->reqdata.path,
2037 (bool)(conn->protocol&PROT_HTTPS?TRUE:FALSE));
2038 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
2040 if(co) {
2041 struct Cookie *store=co;
2042 /* now loop through all cookies that matched */
2043 while(co) {
2044 if(co->value) {
2045 if(0 == count) {
2046 result = add_bufferf(req_buffer, "Cookie: ");
2047 if(result)
2048 break;
2050 result = add_bufferf(req_buffer,
2051 "%s%s=%s", count?"; ":"",
2052 co->name, co->value);
2053 if(result)
2054 break;
2055 count++;
2057 co = co->next; /* next cookie please */
2059 Curl_cookie_freelist(store); /* free the cookie list */
2061 if(addcookies && (CURLE_OK == result)) {
2062 if(!count)
2063 result = add_bufferf(req_buffer, "Cookie: ");
2064 if(CURLE_OK == result) {
2065 result = add_bufferf(req_buffer, "%s%s",
2066 count?"; ":"",
2067 addcookies);
2068 count++;
2071 if(count && (CURLE_OK == result))
2072 result = add_buffer(req_buffer, "\r\n", 2);
2074 if(result)
2075 return result;
2077 #endif
2079 if(data->set.timecondition) {
2080 struct tm *tm;
2082 /* Phil Karn (Fri, 13 Apr 2001) pointed out that the If-Modified-Since
2083 * header family should have their times set in GMT as RFC2616 defines:
2084 * "All HTTP date/time stamps MUST be represented in Greenwich Mean Time
2085 * (GMT), without exception. For the purposes of HTTP, GMT is exactly
2086 * equal to UTC (Coordinated Universal Time)." (see page 20 of RFC2616).
2089 #ifdef HAVE_GMTIME_R
2090 /* thread-safe version */
2091 struct tm keeptime;
2092 tm = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
2093 #else
2094 tm = gmtime(&data->set.timevalue);
2095 #endif
2097 /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
2098 snprintf(buf, BUFSIZE-1,
2099 "%s, %02d %s %4d %02d:%02d:%02d GMT",
2100 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2101 tm->tm_mday,
2102 Curl_month[tm->tm_mon],
2103 tm->tm_year + 1900,
2104 tm->tm_hour,
2105 tm->tm_min,
2106 tm->tm_sec);
2108 switch(data->set.timecondition) {
2109 case CURL_TIMECOND_IFMODSINCE:
2110 default:
2111 result = add_bufferf(req_buffer,
2112 "If-Modified-Since: %s\r\n", buf);
2113 break;
2114 case CURL_TIMECOND_IFUNMODSINCE:
2115 result = add_bufferf(req_buffer,
2116 "If-Unmodified-Since: %s\r\n", buf);
2117 break;
2118 case CURL_TIMECOND_LASTMOD:
2119 result = add_bufferf(req_buffer,
2120 "Last-Modified: %s\r\n", buf);
2121 break;
2123 if(result)
2124 return result;
2127 result = add_custom_headers(conn, req_buffer);
2128 if(result)
2129 return result;
2131 http->postdata = NULL; /* nothing to post at this point */
2132 Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
2134 /* If 'authdone' is FALSE, we must not set the write socket index to the
2135 Curl_transfer() call below, as we're not ready to actually upload any
2136 data yet. */
2138 switch(httpreq) {
2140 case HTTPREQ_POST_FORM:
2141 if(!http->sendit || conn->bits.authneg) {
2142 /* nothing to post! */
2143 result = add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
2144 if(result)
2145 return result;
2147 result = add_buffer_send(req_buffer, conn,
2148 &data->info.request_size, 0, FIRSTSOCKET);
2149 if(result)
2150 failf(data, "Failed sending POST request");
2151 else
2152 /* setup variables for the upcoming transfer */
2153 result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2154 &http->readbytecount,
2155 -1, NULL);
2156 break;
2159 if(Curl_FormInit(&http->form, http->sendit)) {
2160 failf(data, "Internal HTTP POST error!");
2161 return CURLE_HTTP_POST_ERROR;
2164 /* set the read function to read from the generated form data */
2165 conn->fread = (curl_read_callback)Curl_FormReader;
2166 conn->fread_in = &http->form;
2168 http->sending = HTTPSEND_BODY;
2170 if(!conn->bits.upload_chunky) {
2171 /* only add Content-Length if not uploading chunked */
2172 result = add_bufferf(req_buffer,
2173 "Content-Length: %" FORMAT_OFF_T "\r\n",
2174 http->postsize);
2175 if(result)
2176 return result;
2179 result = expect100(data, req_buffer);
2180 if(result)
2181 return result;
2185 /* Get Content-Type: line from Curl_formpostheader.
2187 char *contentType;
2188 size_t linelength=0;
2189 contentType = Curl_formpostheader((void *)&http->form,
2190 &linelength);
2191 if(!contentType) {
2192 failf(data, "Could not get Content-Type header line!");
2193 return CURLE_HTTP_POST_ERROR;
2196 result = add_buffer(req_buffer, contentType, linelength);
2197 if(result)
2198 return result;
2201 /* make the request end in a true CRLF */
2202 result = add_buffer(req_buffer, "\r\n", 2);
2203 if(result)
2204 return result;
2206 /* set upload size to the progress meter */
2207 Curl_pgrsSetUploadSize(data, http->postsize);
2209 /* fire away the whole request to the server */
2210 result = add_buffer_send(req_buffer, conn,
2211 &data->info.request_size, 0, FIRSTSOCKET);
2212 if(result)
2213 failf(data, "Failed sending POST request");
2214 else
2215 /* setup variables for the upcoming transfer */
2216 result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2217 &http->readbytecount,
2218 FIRSTSOCKET,
2219 &http->writebytecount);
2221 if(result) {
2222 Curl_formclean(&http->sendit); /* free that whole lot */
2223 return result;
2225 #ifdef CURL_DOES_CONVERSIONS
2226 /* time to convert the form data... */
2227 result = Curl_formconvert(data, http->sendit);
2228 if(result) {
2229 Curl_formclean(&http->sendit); /* free that whole lot */
2230 return result;
2232 #endif /* CURL_DOES_CONVERSIONS */
2233 break;
2235 case HTTPREQ_PUT: /* Let's PUT the data to the server! */
2237 if(conn->bits.authneg)
2238 postsize = 0;
2239 else
2240 postsize = data->set.infilesize;
2242 if((postsize != -1) && !conn->bits.upload_chunky) {
2243 /* only add Content-Length if not uploading chunked */
2244 result = add_bufferf(req_buffer,
2245 "Content-Length: %" FORMAT_OFF_T "\r\n",
2246 postsize );
2247 if(result)
2248 return result;
2251 result = expect100(data, req_buffer);
2252 if(result)
2253 return result;
2255 result = add_buffer(req_buffer, "\r\n", 2); /* end of headers */
2256 if(result)
2257 return result;
2259 /* set the upload size to the progress meter */
2260 Curl_pgrsSetUploadSize(data, postsize);
2262 /* this sends the buffer and frees all the buffer resources */
2263 result = add_buffer_send(req_buffer, conn,
2264 &data->info.request_size, 0, FIRSTSOCKET);
2265 if(result)
2266 failf(data, "Failed sending PUT request");
2267 else
2268 /* prepare for transfer */
2269 result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2270 &http->readbytecount,
2271 postsize?FIRSTSOCKET:-1,
2272 postsize?&http->writebytecount:NULL);
2273 if(result)
2274 return result;
2275 break;
2277 case HTTPREQ_POST:
2278 /* this is the simple POST, using x-www-form-urlencoded style */
2280 if(conn->bits.authneg)
2281 postsize = 0;
2282 else
2283 /* figure out the size of the postfields */
2284 postsize = (data->set.postfieldsize != -1)?
2285 data->set.postfieldsize:
2286 (data->set.postfields?(curl_off_t)strlen(data->set.postfields):0);
2288 if(!conn->bits.upload_chunky) {
2289 /* We only set Content-Length and allow a custom Content-Length if
2290 we don't upload data chunked, as RFC2616 forbids us to set both
2291 kinds of headers (Transfer-Encoding: chunked and Content-Length) */
2293 if(!checkheaders(data, "Content-Length:")) {
2294 /* we allow replacing this header, although it isn't very wise to
2295 actually set your own */
2296 result = add_bufferf(req_buffer,
2297 "Content-Length: %" FORMAT_OFF_T"\r\n",
2298 postsize);
2299 if(result)
2300 return result;
2304 if(!checkheaders(data, "Content-Type:")) {
2305 result = add_bufferf(req_buffer,
2306 "Content-Type: application/x-www-form-urlencoded\r\n");
2307 if(result)
2308 return result;
2311 if(data->set.postfields) {
2313 /* for really small posts we don't use Expect: headers at all, and for
2314 the somewhat bigger ones we allow the app to disable it */
2315 if(postsize > TINY_INITIAL_POST_SIZE) {
2316 result = expect100(data, req_buffer);
2317 if(result)
2318 return result;
2320 else
2321 data->state.expect100header = FALSE;
2323 if(!data->state.expect100header &&
2324 (postsize < MAX_INITIAL_POST_SIZE)) {
2325 /* if we don't use expect:-100 AND
2326 postsize is less than MAX_INITIAL_POST_SIZE
2328 then append the post data to the HTTP request header. This limit
2329 is no magic limit but only set to prevent really huge POSTs to
2330 get the data duplicated with malloc() and family. */
2332 result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2333 if(result)
2334 return result;
2336 if(!conn->bits.upload_chunky) {
2337 /* We're not sending it 'chunked', append it to the request
2338 already now to reduce the number if send() calls */
2339 result = add_buffer(req_buffer, data->set.postfields,
2340 (size_t)postsize);
2341 included_body = postsize;
2343 else {
2344 /* Append the POST data chunky-style */
2345 result = add_bufferf(req_buffer, "%x\r\n", (int)postsize);
2346 if(CURLE_OK == result)
2347 result = add_buffer(req_buffer, data->set.postfields,
2348 (size_t)postsize);
2349 if(CURLE_OK == result)
2350 result = add_buffer(req_buffer,
2351 "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7);
2352 /* CR LF 0 CR LF CR LF */
2353 included_body = postsize + 7;
2355 if(result)
2356 return result;
2358 else {
2359 /* A huge POST coming up, do data separate from the request */
2360 http->postsize = postsize;
2361 http->postdata = data->set.postfields;
2363 http->sending = HTTPSEND_BODY;
2365 conn->fread = (curl_read_callback)readmoredata;
2366 conn->fread_in = (void *)conn;
2368 /* set the upload size to the progress meter */
2369 Curl_pgrsSetUploadSize(data, http->postsize);
2371 add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2374 else {
2375 add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2377 if(data->set.postfieldsize) {
2378 /* set the upload size to the progress meter */
2379 Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
2381 /* set the pointer to mark that we will send the post body using
2382 the read callback */
2383 http->postdata = (char *)&http->postdata;
2386 /* issue the request */
2387 result = add_buffer_send(req_buffer, conn, &data->info.request_size,
2388 (size_t)included_body, FIRSTSOCKET);
2390 if(result)
2391 failf(data, "Failed sending HTTP POST request");
2392 else
2393 result =
2394 Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2395 &http->readbytecount,
2396 http->postdata?FIRSTSOCKET:-1,
2397 http->postdata?&http->writebytecount:NULL);
2398 break;
2400 default:
2401 add_buffer(req_buffer, "\r\n", 2);
2403 /* issue the request */
2404 result = add_buffer_send(req_buffer, conn,
2405 &data->info.request_size, 0, FIRSTSOCKET);
2407 if(result)
2408 failf(data, "Failed sending HTTP request");
2409 else
2410 /* HTTP GET/HEAD download: */
2411 result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2412 &http->readbytecount,
2413 http->postdata?FIRSTSOCKET:-1,
2414 http->postdata?&http->writebytecount:NULL);
2416 if(result)
2417 return result;
2420 return CURLE_OK;
2422 #endif