1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
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.
13 *
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.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * $Id: http.c,v 1.412 2009-02-24 08:30:09 bagder Exp $
22 ***************************************************************************/
23
24 #include "setup.h"
25
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
34 #ifdef WIN32
35 #include <time.h>
36 #include <io.h>
37 #else
38 #ifdef HAVE_SYS_SOCKET_H
39 #include <sys/socket.h>
40 #endif
41 #ifdef HAVE_NETINET_IN_H
42 #include <netinet/in.h>
43 #endif
44 #ifdef HAVE_SYS_TIME_H
45 #include <sys/time.h>
46 #endif
47
48 #ifdef HAVE_TIME_H
49 #ifdef TIME_WITH_SYS_TIME
50 #include <time.h>
51 #endif
52 #endif
53
54 #ifdef HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
57 #ifdef HAVE_NETDB_H
58 #include <netdb.h>
59 #endif
60 #ifdef HAVE_ARPA_INET_H
61 #include <arpa/inet.h>
62 #endif
63 #ifdef HAVE_NET_IF_H
64 #include <net/if.h>
65 #endif
66 #ifdef HAVE_SYS_IOCTL_H
67 #include <sys/ioctl.h>
68 #endif
69
70 #ifdef HAVE_SYS_PARAM_H
71 #include <sys/param.h>
72 #endif
73
74 #endif
75
76 #include "urldata.h"
77 #include <curl/curl.h>
78 #include "transfer.h"
79 #include "sendf.h"
80 #include "easyif.h" /* for Curl_convert_... prototypes */
81 #include "formdata.h"
82 #include "progress.h"
83 #include "curl_base64.h"
84 #include "cookie.h"
85 #include "strequal.h"
86 #include "sslgen.h"
87 #include "http_digest.h"
88 #include "http_ntlm.h"
89 #include "http_negotiate.h"
90 #include "url.h"
91 #include "share.h"
92 #include "hostip.h"
93 #include "http.h"
94 #include "memory.h"
95 #include "select.h"
96 #include "parsedate.h" /* for the week day and month names */
97 #include "strtoofft.h"
98 #include "multiif.h"
99 #include "rawstr.h"
100
101 #define _MPRINTF_REPLACE /* use our functions only */
102 #include <curl/mprintf.h>
103
104 /* The last #include file should be: */
105 #include "memdebug.h"
106
107 /* Default proxy timeout in milliseconds */
108 #define PROXY_TIMEOUT (3600*1000)
109
110 /*
111 * Forward declarations.
112 */
113
114 static int http_getsock_do(struct connectdata *conn,
115 curl_socket_t *socks,
116 int numsocks);
117 #ifdef USE_SSL
118 static CURLcode https_connecting(struct connectdata *conn, bool *done);
119 static int https_getsock(struct connectdata *conn,
120 curl_socket_t *socks,
121 int numsocks);
122 #else
123 #define https_connecting(x,y) CURLE_COULDNT_CONNECT
124 #endif
125
126 /*
127 * HTTP handler interface.
128 */
129 const struct Curl_handler Curl_handler_http = {
130 "HTTP", /* scheme */
131 ZERO_NULL, /* setup_connection */
132 Curl_http, /* do_it */
133 Curl_http_done, /* done */
134 ZERO_NULL, /* do_more */
135 Curl_http_connect, /* connect_it */
136 ZERO_NULL, /* connecting */
137 ZERO_NULL, /* doing */
138 ZERO_NULL, /* proto_getsock */
139 http_getsock_do, /* doing_getsock */
140 ZERO_NULL, /* perform_getsock */
141 ZERO_NULL, /* disconnect */
142 PORT_HTTP, /* defport */
143 PROT_HTTP, /* protocol */
144 };
145
146 #ifdef USE_SSL
147 /*
148 * HTTPS handler interface.
149 */
150 const struct Curl_handler Curl_handler_https = {
151 "HTTPS", /* scheme */
152 ZERO_NULL, /* setup_connection */
153 Curl_http, /* do_it */
154 Curl_http_done, /* done */
155 ZERO_NULL, /* do_more */
156 Curl_http_connect, /* connect_it */
157 https_connecting, /* connecting */
158 ZERO_NULL, /* doing */
159 https_getsock, /* proto_getsock */
160 http_getsock_do, /* doing_getsock */
161 ZERO_NULL, /* perform_getsock */
162 ZERO_NULL, /* disconnect */
163 PORT_HTTPS, /* defport */
164 PROT_HTTP | PROT_HTTPS | PROT_SSL /* protocol */
165 };
166 #endif
167
168
169 /*
170 * checkheaders() checks the linked list of custom HTTP headers for a
171 * particular header (prefix).
172 *
173 * Returns a pointer to the first matching header or NULL if none matched.
174 */
checkheaders(struct SessionHandle * data,const char * thisheader)175 static char *checkheaders(struct SessionHandle *data, const char *thisheader)
176 {
177 struct curl_slist *head;
178 size_t thislen = strlen(thisheader);
179
180 for(head = data->set.headers; head; head=head->next) {
181 if(Curl_raw_nequal(head->data, thisheader, thislen))
182 return head->data;
183 }
184 return NULL;
185 }
186
187 /*
188 * Strip off leading and trailing whitespace from the value in the
189 * given HTTP header line and return a strdupped copy. Returns NULL in
190 * case of allocation failure. Returns an empty string if the header value
191 * consists entirely of whitespace.
192 */
Curl_copy_header_value(const char * h)193 char *Curl_copy_header_value(const char *h)
194 {
195 const char *start;
196 const char *end;
197 char *value;
198 size_t len;
199
200 DEBUGASSERT(h);
201
202 /* Find the end of the header name */
203 while (*h && (*h != ':'))
204 ++h;
205
206 if (*h)
207 /* Skip over colon */
208 ++h;
209
210 /* Find the first non-space letter */
211 start = h;
212 while(*start && ISSPACE(*start))
213 start++;
214
215 /* data is in the host encoding so
216 use '\r' and '\n' instead of 0x0d and 0x0a */
217 end = strchr(start, '\r');
218 if(!end)
219 end = strchr(start, '\n');
220 if(!end)
221 end = strchr(start, '\0');
222 if(!end)
223 return NULL;
224
225 /* skip all trailing space letters */
226 while((end > start) && ISSPACE(*end))
227 end--;
228
229 /* get length of the type */
230 len = end-start+1;
231
232 value = malloc(len + 1);
233 if(!value)
234 return NULL;
235
236 memcpy(value, start, len);
237 value[len] = 0; /* zero terminate */
238
239 return value;
240 }
241
242 /*
243 * http_output_basic() sets up an Authorization: header (or the proxy version)
244 * for HTTP Basic authentication.
245 *
246 * Returns CURLcode.
247 */
http_output_basic(struct connectdata * conn,bool proxy)248 static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
249 {
250 char *authorization;
251 struct SessionHandle *data=conn->data;
252 char **userp;
253 const char *user;
254 const char *pwd;
255
256 if(proxy) {
257 userp = &conn->allocptr.proxyuserpwd;
258 user = conn->proxyuser;
259 pwd = conn->proxypasswd;
260 }
261 else {
262 userp = &conn->allocptr.userpwd;
263 user = conn->user;
264 pwd = conn->passwd;
265 }
266
267 snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd);
268 if(Curl_base64_encode(data, data->state.buffer,
269 strlen(data->state.buffer),
270 &authorization) > 0) {
271 if(*userp)
272 free(*userp);
273 *userp = aprintf( "%sAuthorization: Basic %s\r\n",
274 proxy?"Proxy-":"",
275 authorization);
276 free(authorization);
277 if(!*userp)
278 return CURLE_OUT_OF_MEMORY;
279 }
280 else
281 return CURLE_OUT_OF_MEMORY;
282 return CURLE_OK;
283 }
284
285 /* pickoneauth() selects the most favourable authentication method from the
286 * ones available and the ones we want.
287 *
288 * return TRUE if one was picked
289 */
pickoneauth(struct auth * pick)290 static bool pickoneauth(struct auth *pick)
291 {
292 bool picked;
293 /* only deal with authentication we want */
294 long avail = pick->avail & pick->want;
295 picked = TRUE;
296
297 /* The order of these checks is highly relevant, as this will be the order
298 of preference in case of the existence of multiple accepted types. */
299 if(avail & CURLAUTH_GSSNEGOTIATE)
300 pick->picked = CURLAUTH_GSSNEGOTIATE;
301 else if(avail & CURLAUTH_DIGEST)
302 pick->picked = CURLAUTH_DIGEST;
303 else if(avail & CURLAUTH_NTLM)
304 pick->picked = CURLAUTH_NTLM;
305 else if(avail & CURLAUTH_BASIC)
306 pick->picked = CURLAUTH_BASIC;
307 else {
308 pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */
309 picked = FALSE;
310 }
311 pick->avail = CURLAUTH_NONE; /* clear it here */
312
313 return picked;
314 }
315
316 /*
317 * Curl_http_perhapsrewind()
318 *
319 * If we are doing POST or PUT {
320 * If we have more data to send {
321 * If we are doing NTLM {
322 * Keep sending since we must not disconnect
323 * }
324 * else {
325 * If there is more than just a little data left to send, close
326 * the current connection by force.
327 * }
328 * }
329 * If we have sent any data {
330 * If we don't have track of all the data {
331 * call app to tell it to rewind
332 * }
333 * else {
334 * rewind internally so that the operation can restart fine
335 * }
336 * }
337 * }
338 */
Curl_http_perhapsrewind(struct connectdata * conn)339 CURLcode Curl_http_perhapsrewind(struct connectdata *conn)
340 {
341 struct SessionHandle *data = conn->data;
342 struct HTTP *http = data->state.proto.http;
343 curl_off_t bytessent;
344 curl_off_t expectsend = -1; /* default is unknown */
345
346 if(!http || !(conn->protocol & PROT_HTTP))
347 /* If this is still NULL, we have not reach very far and we can
348 safely skip this rewinding stuff, or this is attempted to get used
349 when HTTP isn't activated */
350 return CURLE_OK;
351
352 switch(data->set.httpreq) {
353 case HTTPREQ_GET:
354 case HTTPREQ_HEAD:
355 return CURLE_OK;
356 default:
357 break;
358 }
359
360 bytessent = http->writebytecount;
361
362 if(conn->bits.authneg)
363 /* This is a state where we are known to be negotiating and we don't send
364 any data then. */
365 expectsend = 0;
366 else {
367 /* figure out how much data we are expected to send */
368 switch(data->set.httpreq) {
369 case HTTPREQ_POST:
370 if(data->set.postfieldsize != -1)
371 expectsend = data->set.postfieldsize;
372 break;
373 case HTTPREQ_PUT:
374 if(data->set.infilesize != -1)
375 expectsend = data->set.infilesize;
376 break;
377 case HTTPREQ_POST_FORM:
378 expectsend = http->postsize;
379 break;
380 default:
381 break;
382 }
383 }
384
385 conn->bits.rewindaftersend = FALSE; /* default */
386
387 if((expectsend == -1) || (expectsend > bytessent)) {
388 /* There is still data left to send */
389 if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
390 (data->state.authhost.picked == CURLAUTH_NTLM)) {
391 if(((expectsend - bytessent) < 2000) ||
392 (conn->ntlm.state != NTLMSTATE_NONE)) {
393 /* The NTLM-negotiation has started *OR* there is just a little (<2K)
394 data left to send, keep on sending. */
395
396 /* rewind data when completely done sending! */
397 if(!conn->bits.authneg)
398 conn->bits.rewindaftersend = TRUE;
399
400 return CURLE_OK;
401 }
402 if(conn->bits.close)
403 /* this is already marked to get closed */
404 return CURLE_OK;
405
406 infof(data, "NTLM send, close instead of sending %" FORMAT_OFF_T
407 " bytes\n", (curl_off_t)(expectsend - bytessent));
408 }
409
410 /* This is not NTLM or NTLM with many bytes left to send: close
411 */
412 conn->bits.close = TRUE;
413 data->req.size = 0; /* don't download any more than 0 bytes */
414
415 /* There still is data left to send, but this connection is marked for
416 closure so we can safely do the rewind right now */
417 }
418
419 if(bytessent)
420 /* we rewind now at once since if we already sent something */
421 return Curl_readrewind(conn);
422
423 return CURLE_OK;
424 }
425
426 /*
427 * Curl_http_auth_act() gets called when all HTTP headers have been received
428 * and it checks what authentication methods that are available and decides
429 * which one (if any) to use. It will set 'newurl' if an auth method was
430 * picked.
431 */
432
Curl_http_auth_act(struct connectdata * conn)433 CURLcode Curl_http_auth_act(struct connectdata *conn)
434 {
435 struct SessionHandle *data = conn->data;
436 bool pickhost = FALSE;
437 bool pickproxy = FALSE;
438 CURLcode code = CURLE_OK;
439
440 if(100 <= data->req.httpcode && 199 >= data->req.httpcode)
441 /* this is a transient response code, ignore */
442 return CURLE_OK;
443
444 if(data->state.authproblem)
445 return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
446
447 if(conn->bits.user_passwd &&
448 ((data->req.httpcode == 401) ||
449 (conn->bits.authneg && data->req.httpcode < 300))) {
450 pickhost = pickoneauth(&data->state.authhost);
451 if(!pickhost)
452 data->state.authproblem = TRUE;
453 }
454 if(conn->bits.proxy_user_passwd &&
455 ((data->req.httpcode == 407) ||
456 (conn->bits.authneg && data->req.httpcode < 300))) {
457 pickproxy = pickoneauth(&data->state.authproxy);
458 if(!pickproxy)
459 data->state.authproblem = TRUE;
460 }
461
462 if(pickhost || pickproxy) {
463 /* In case this is GSS auth, the newurl field is already allocated so
464 we must make sure to free it before allocating a new one. As figured
465 out in bug #2284386 */
466 Curl_safefree(data->req.newurl);
467 data->req.newurl = strdup(data->change.url); /* clone URL */
468 if(!data->req.newurl)
469 return CURLE_OUT_OF_MEMORY;
470
471 if((data->set.httpreq != HTTPREQ_GET) &&
472 (data->set.httpreq != HTTPREQ_HEAD) &&
473 !conn->bits.rewindaftersend) {
474 code = Curl_http_perhapsrewind(conn);
475 if(code)
476 return code;
477 }
478 }
479
480 else if((data->req.httpcode < 300) &&
481 (!data->state.authhost.done) &&
482 conn->bits.authneg) {
483 /* no (known) authentication available,
484 authentication is not "done" yet and
485 no authentication seems to be required and
486 we didn't try HEAD or GET */
487 if((data->set.httpreq != HTTPREQ_GET) &&
488 (data->set.httpreq != HTTPREQ_HEAD)) {
489 data->req.newurl = strdup(data->change.url); /* clone URL */
490 if(!data->req.newurl)
491 return CURLE_OUT_OF_MEMORY;
492 data->state.authhost.done = TRUE;
493 }
494 }
495 if(Curl_http_should_fail(conn)) {
496 failf (data, "The requested URL returned error: %d",
497 data->req.httpcode);
498 code = CURLE_HTTP_RETURNED_ERROR;
499 }
500
501 return code;
502 }
503
504
505 /*
506 * Output the correct authentication header depending on the auth type
507 * and whether or not it is to a proxy.
508 */
509 static CURLcode
output_auth_headers(struct connectdata * conn,struct auth * authstatus,const char * request,const char * path,bool proxy)510 output_auth_headers(struct connectdata *conn,
511 struct auth *authstatus,
512 const char *request,
513 const char *path,
514 bool proxy)
515 {
516 struct SessionHandle *data = conn->data;
517 const char *auth=NULL;
518 CURLcode result = CURLE_OK;
519 #ifdef HAVE_GSSAPI
520 struct negotiatedata *negdata = proxy?
521 &data->state.proxyneg:&data->state.negotiate;
522 #endif
523
524 #ifndef CURL_DISABLE_CRYPTO_AUTH
525 (void)request;
526 (void)path;
527 #endif
528
529 #ifdef HAVE_GSSAPI
530 if((authstatus->picked == CURLAUTH_GSSNEGOTIATE) &&
531 negdata->context && !GSS_ERROR(negdata->status)) {
532 auth="GSS-Negotiate";
533 result = Curl_output_negotiate(conn, proxy);
534 if(result)
535 return result;
536 authstatus->done = TRUE;
537 negdata->state = GSS_AUTHSENT;
538 }
539 else
540 #endif
541 #ifdef USE_NTLM
542 if(authstatus->picked == CURLAUTH_NTLM) {
543 auth="NTLM";
544 result = Curl_output_ntlm(conn, proxy);
545 if(result)
546 return result;
547 }
548 else
549 #endif
550 #ifndef CURL_DISABLE_CRYPTO_AUTH
551 if(authstatus->picked == CURLAUTH_DIGEST) {
552 auth="Digest";
553 result = Curl_output_digest(conn,
554 proxy,
555 (const unsigned char *)request,
556 (const unsigned char *)path);
557 if(result)
558 return result;
559 }
560 else
561 #endif
562 if(authstatus->picked == CURLAUTH_BASIC) {
563 /* Basic */
564 if((proxy && conn->bits.proxy_user_passwd &&
565 !checkheaders(data, "Proxy-authorization:")) ||
566 (!proxy && conn->bits.user_passwd &&
567 !checkheaders(data, "Authorization:"))) {
568 auth="Basic";
569 result = http_output_basic(conn, proxy);
570 if(result)
571 return result;
572 }
573 /* NOTE: this function should set 'done' TRUE, as the other auth
574 functions work that way */
575 authstatus->done = TRUE;
576 }
577
578 if(auth) {
579 infof(data, "%s auth using %s with user '%s'\n",
580 proxy?"Proxy":"Server", auth,
581 proxy?(conn->proxyuser?conn->proxyuser:""):
582 (conn->user?conn->user:""));
583 authstatus->multi = (bool)(!authstatus->done);
584 }
585 else
586 authstatus->multi = FALSE;
587
588 return CURLE_OK;
589 }
590
591 /**
592 * Curl_http_output_auth() setups the authentication headers for the
593 * host/proxy and the correct authentication
594 * method. conn->data->state.authdone is set to TRUE when authentication is
595 * done.
596 *
597 * @param conn all information about the current connection
598 * @param request pointer to the request keyword
599 * @param path pointer to the requested path
600 * @param proxytunnel boolean if this is the request setting up a "proxy
601 * tunnel"
602 *
603 * @returns CURLcode
604 */
605 static CURLcode
http_output_auth(struct connectdata * conn,const char * request,const char * path,bool proxytunnel)606 http_output_auth(struct connectdata *conn,
607 const char *request,
608 const char *path,
609 bool proxytunnel) /* TRUE if this is the request setting
610 up the proxy tunnel */
611 {
612 CURLcode result = CURLE_OK;
613 struct SessionHandle *data = conn->data;
614 struct auth *authhost;
615 struct auth *authproxy;
616
617 DEBUGASSERT(data);
618
619 authhost = &data->state.authhost;
620 authproxy = &data->state.authproxy;
621
622 if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
623 conn->bits.user_passwd)
624 /* continue please */ ;
625 else {
626 authhost->done = TRUE;
627 authproxy->done = TRUE;
628 return CURLE_OK; /* no authentication with no user or password */
629 }
630
631 if(authhost->want && !authhost->picked)
632 /* The app has selected one or more methods, but none has been picked
633 so far by a server round-trip. Then we set the picked one to the
634 want one, and if this is one single bit it'll be used instantly. */
635 authhost->picked = authhost->want;
636
637 if(authproxy->want && !authproxy->picked)
638 /* The app has selected one or more methods, but none has been picked so
639 far by a proxy round-trip. Then we set the picked one to the want one,
640 and if this is one single bit it'll be used instantly. */
641 authproxy->picked = authproxy->want;
642
643 #ifndef CURL_DISABLE_PROXY
644 /* Send proxy authentication header if needed */
645 if(conn->bits.httpproxy &&
646 (conn->bits.tunnel_proxy == proxytunnel)) {
647 result = output_auth_headers(conn, authproxy, request, path, TRUE);
648 if(result)
649 return result;
650 }
651 else
652 #else
653 (void)proxytunnel;
654 #endif /* CURL_DISABLE_PROXY */
655 /* we have no proxy so let's pretend we're done authenticating
656 with it */
657 authproxy->done = TRUE;
658
659 /* To prevent the user+password to get sent to other than the original
660 host due to a location-follow, we do some weirdo checks here */
661 if(!data->state.this_is_a_follow ||
662 conn->bits.netrc ||
663 !data->state.first_host ||
664 data->set.http_disable_hostname_check_before_authentication ||
665 Curl_raw_equal(data->state.first_host, conn->host.name)) {
666 result = output_auth_headers(conn, authhost, request, path, FALSE);
667 }
668 else
669 authhost->done = TRUE;
670
671 return result;
672 }
673
674
675 /*
676 * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
677 * headers. They are dealt with both in the transfer.c main loop and in the
678 * proxy CONNECT loop.
679 */
680
Curl_http_input_auth(struct connectdata * conn,int httpcode,const char * header)681 CURLcode Curl_http_input_auth(struct connectdata *conn,
682 int httpcode,
683 const char *header) /* the first non-space */
684 {
685 /*
686 * This resource requires authentication
687 */
688 struct SessionHandle *data = conn->data;
689
690 long *availp;
691 const char *start;
692 struct auth *authp;
693
694 if(httpcode == 407) {
695 start = header+strlen("Proxy-authenticate:");
696 availp = &data->info.proxyauthavail;
697 authp = &data->state.authproxy;
698 }
699 else {
700 start = header+strlen("WWW-Authenticate:");
701 availp = &data->info.httpauthavail;
702 authp = &data->state.authhost;
703 }
704
705 /* pass all white spaces */
706 while(*start && ISSPACE(*start))
707 start++;
708
709 /*
710 * Here we check if we want the specific single authentication (using ==) and
711 * if we do, we initiate usage of it.
712 *
713 * If the provided authentication is wanted as one out of several accepted
714 * types (using &), we OR this authentication type to the authavail
715 * variable.
716 *
717 * Note:
718 *
719 * ->picked is first set to the 'want' value (one or more bits) before the
720 * request is sent, and then it is again set _after_ all response 401/407
721 * headers have been received but then only to a single preferred method
722 * (bit).
723 *
724 */
725
726 #ifdef HAVE_GSSAPI
727 if(checkprefix("GSS-Negotiate", start) ||
728 checkprefix("Negotiate", start)) {
729 int neg;
730 *availp |= CURLAUTH_GSSNEGOTIATE;
731 authp->avail |= CURLAUTH_GSSNEGOTIATE;
732
733 if(data->state.negotiate.state == GSS_AUTHSENT) {
734 /* if we sent GSS authentication in the outgoing request and we get this
735 back, we're in trouble */
736 infof(data, "Authentication problem. Ignoring this.\n");
737 data->state.authproblem = TRUE;
738 }
739 else {
740 neg = Curl_input_negotiate(conn, (bool)(httpcode == 407), start);
741 if(neg == 0) {
742 DEBUGASSERT(!data->req.newurl);
743 data->req.newurl = strdup(data->change.url);
744 if(!data->req.newurl)
745 return CURLE_OUT_OF_MEMORY;
746 data->state.authproblem = FALSE;
747 /* we received GSS auth info and we dealt with it fine */
748 data->state.negotiate.state = GSS_AUTHRECV;
749 }
750 }
751 }
752 else
753 #endif
754 #ifdef USE_NTLM
755 /* NTLM support requires the SSL crypto libs */
756 if(checkprefix("NTLM", start)) {
757 *availp |= CURLAUTH_NTLM;
758 authp->avail |= CURLAUTH_NTLM;
759 if(authp->picked == CURLAUTH_NTLM) {
760 /* NTLM authentication is picked and activated */
761 CURLntlm ntlm =
762 Curl_input_ntlm(conn, (bool)(httpcode == 407), start);
763
764 if(CURLNTLM_BAD != ntlm)
765 data->state.authproblem = FALSE;
766 else {
767 infof(data, "Authentication problem. Ignoring this.\n");
768 data->state.authproblem = TRUE;
769 }
770 }
771 }
772 else
773 #endif
774 #ifndef CURL_DISABLE_CRYPTO_AUTH
775 if(checkprefix("Digest", start)) {
776 if((authp->avail & CURLAUTH_DIGEST) != 0) {
777 infof(data, "Ignoring duplicate digest auth header.\n");
778 }
779 else {
780 CURLdigest dig;
781 *availp |= CURLAUTH_DIGEST;
782 authp->avail |= CURLAUTH_DIGEST;
783
784 /* We call this function on input Digest headers even if Digest
785 * authentication isn't activated yet, as we need to store the
786 * incoming data from this header in case we are gonna use Digest. */
787 dig = Curl_input_digest(conn, (bool)(httpcode == 407), start);
788
789 if(CURLDIGEST_FINE != dig) {
790 infof(data, "Authentication problem. Ignoring this.\n");
791 data->state.authproblem = TRUE;
792 }
793 }
794 }
795 else
796 #endif
797 if(checkprefix("Basic", start)) {
798 *availp |= CURLAUTH_BASIC;
799 authp->avail |= CURLAUTH_BASIC;
800 if(authp->picked == CURLAUTH_BASIC) {
801 /* We asked for Basic authentication but got a 40X back
802 anyway, which basically means our name+password isn't
803 valid. */
804 authp->avail = CURLAUTH_NONE;
805 infof(data, "Authentication problem. Ignoring this.\n");
806 data->state.authproblem = TRUE;
807 }
808 }
809
810 return CURLE_OK;
811 }
812
813 /**
814 * Curl_http_should_fail() determines whether an HTTP response has gotten us
815 * into an error state or not.
816 *
817 * @param conn all information about the current connection
818 *
819 * @retval 0 communications should continue
820 *
821 * @retval 1 communications should not continue
822 */
Curl_http_should_fail(struct connectdata * conn)823 int Curl_http_should_fail(struct connectdata *conn)
824 {
825 struct SessionHandle *data;
826 int httpcode;
827
828 DEBUGASSERT(conn);
829 data = conn->data;
830 DEBUGASSERT(data);
831
832 httpcode = data->req.httpcode;
833
834 /*
835 ** If we haven't been asked to fail on error,
836 ** don't fail.
837 */
838 if(!data->set.http_fail_on_error)
839 return 0;
840
841 /*
842 ** Any code < 400 is never terminal.
843 */
844 if(httpcode < 400)
845 return 0;
846
847 if(data->state.resume_from &&
848 (data->set.httpreq==HTTPREQ_GET) &&
849 (httpcode == 416)) {
850 /* "Requested Range Not Satisfiable", just proceed and
851 pretend this is no error */
852 return 0;
853 }
854
855 /*
856 ** Any code >= 400 that's not 401 or 407 is always
857 ** a terminal error
858 */
859 if((httpcode != 401) &&
860 (httpcode != 407))
861 return 1;
862
863 /*
864 ** All we have left to deal with is 401 and 407
865 */
866 DEBUGASSERT((httpcode == 401) || (httpcode == 407));
867
868 /*
869 ** Examine the current authentication state to see if this
870 ** is an error. The idea is for this function to get
871 ** called after processing all the headers in a response
872 ** message. So, if we've been to asked to authenticate a
873 ** particular stage, and we've done it, we're OK. But, if
874 ** we're already completely authenticated, it's not OK to
875 ** get another 401 or 407.
876 **
877 ** It is possible for authentication to go stale such that
878 ** the client needs to reauthenticate. Once that info is
879 ** available, use it here.
880 */
881 #if 0 /* set to 1 when debugging this functionality */
882 infof(data,"%s: authstage = %d\n",__FUNCTION__,data->state.authstage);
883 infof(data,"%s: authwant = 0x%08x\n",__FUNCTION__,data->state.authwant);
884 infof(data,"%s: authavail = 0x%08x\n",__FUNCTION__,data->state.authavail);
885 infof(data,"%s: httpcode = %d\n",__FUNCTION__,k->httpcode);
886 infof(data,"%s: authdone = %d\n",__FUNCTION__,data->state.authdone);
887 infof(data,"%s: newurl = %s\n",__FUNCTION__,data->req.newurl ?
888 data->req.newurl : "(null)");
889 infof(data,"%s: authproblem = %d\n",__FUNCTION__,data->state.authproblem);
890 #endif
891
892 /*
893 ** Either we're not authenticating, or we're supposed to
894 ** be authenticating something else. This is an error.
895 */
896 if((httpcode == 401) && !conn->bits.user_passwd)
897 return TRUE;
898 if((httpcode == 407) && !conn->bits.proxy_user_passwd)
899 return TRUE;
900
901 return data->state.authproblem;
902 }
903
904 /*
905 * readmoredata() is a "fread() emulation" to provide POST and/or request
906 * data. It is used when a huge POST is to be made and the entire chunk wasn't
907 * sent in the first send(). This function will then be called from the
908 * transfer.c loop when more data is to be sent to the peer.
909 *
910 * Returns the amount of bytes it filled the buffer with.
911 */
readmoredata(char * buffer,size_t size,size_t nitems,void * userp)912 static size_t readmoredata(char *buffer,
913 size_t size,
914 size_t nitems,
915 void *userp)
916 {
917 struct connectdata *conn = (struct connectdata *)userp;
918 struct HTTP *http = conn->data->state.proto.http;
919 size_t fullsize = size * nitems;
920
921 if(0 == http->postsize)
922 /* nothing to return */
923 return 0;
924
925 /* make sure that a HTTP request is never sent away chunked! */
926 conn->data->req.forbidchunk = (bool)(http->sending == HTTPSEND_REQUEST);
927
928 if(http->postsize <= (curl_off_t)fullsize) {
929 memcpy(buffer, http->postdata, (size_t)http->postsize);
930 fullsize = (size_t)http->postsize;
931
932 if(http->backup.postsize) {
933 /* move backup data into focus and continue on that */
934 http->postdata = http->backup.postdata;
935 http->postsize = http->backup.postsize;
936 conn->fread_func = http->backup.fread_func;
937 conn->fread_in = http->backup.fread_in;
938
939 http->sending++; /* move one step up */
940
941 http->backup.postsize=0;
942 }
943 else
944 http->postsize = 0;
945
946 return fullsize;
947 }
948
949 memcpy(buffer, http->postdata, fullsize);
950 http->postdata += fullsize;
951 http->postsize -= fullsize;
952
953 return fullsize;
954 }
955
956 /* ------------------------------------------------------------------------- */
957 /*
958 * The add_buffer series of functions are used to build one large memory chunk
959 * from repeated function invokes. Used so that the entire HTTP request can
960 * be sent in one go.
961 */
962
963 struct send_buffer {
964 char *buffer;
965 size_t size_max;
966 size_t size_used;
967 };
968 typedef struct send_buffer send_buffer;
969
970 static CURLcode add_custom_headers(struct connectdata *conn,
971 send_buffer *req_buffer);
972 static CURLcode
973 add_buffer(send_buffer *in, const void *inptr, size_t size);
974
975 /*
976 * add_buffer_init() sets up and returns a fine buffer struct
977 */
978 static
add_buffer_init(void)979 send_buffer *add_buffer_init(void)
980 {
981 return calloc(sizeof(send_buffer), 1);
982 }
983
984 /*
985 * add_buffer_send() sends a header buffer and frees all associated memory.
986 * Body data may be appended to the header data if desired.
987 *
988 * Returns CURLcode
989 */
990 static
add_buffer_send(send_buffer * in,struct connectdata * conn,long * bytes_written,size_t included_body_bytes,int socketindex)991 CURLcode add_buffer_send(send_buffer *in,
992 struct connectdata *conn,
993 long *bytes_written, /* add the number of sent bytes
994 to this counter */
995 size_t included_body_bytes, /* how much of the buffer
996 contains body data */
997 int socketindex)
998
999 {
1000 ssize_t amount;
1001 CURLcode res;
1002 char *ptr;
1003 size_t size;
1004 struct HTTP *http = conn->data->state.proto.http;
1005 size_t sendsize;
1006 curl_socket_t sockfd;
1007 size_t headersize;
1008
1009 DEBUGASSERT(socketindex <= SECONDARYSOCKET);
1010
1011 sockfd = conn->sock[socketindex];
1012
1013 /* The looping below is required since we use non-blocking sockets, but due
1014 to the circumstances we will just loop and try again and again etc */
1015
1016 ptr = in->buffer;
1017 size = in->size_used;
1018
1019 headersize = size - included_body_bytes; /* the initial part that isn't body
1020 is header */
1021
1022 DEBUGASSERT(size > included_body_bytes);
1023
1024 #ifdef CURL_DOES_CONVERSIONS
1025 res = Curl_convert_to_network(conn->data, ptr, headersize);
1026 /* Curl_convert_to_network calls failf if unsuccessful */
1027 if(res != CURLE_OK) {
1028 /* conversion failed, free memory and return to the caller */
1029 if(in->buffer)
1030 free(in->buffer);
1031 free(in);
1032 return res;
1033 }
1034 #endif /* CURL_DOES_CONVERSIONS */
1035
1036 if(conn->protocol & PROT_HTTPS) {
1037 /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
1038 when we speak HTTPS, as if only a fraction of it is sent now, this data
1039 needs to fit into the normal read-callback buffer later on and that
1040 buffer is using this size.
1041 */
1042
1043 sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:size;
1044
1045 /* OpenSSL is very picky and we must send the SAME buffer pointer to the
1046 library when we attempt to re-send this buffer. Sending the same data
1047 is not enough, we must use the exact same address. For this reason, we
1048 must copy the data to the uploadbuffer first, since that is the buffer
1049 we will be using if this send is retried later.
1050 */
1051 memcpy(conn->data->state.uploadbuffer, ptr, sendsize);
1052 ptr = conn->data->state.uploadbuffer;
1053 }
1054 else
1055 sendsize = size;
1056
1057 res = Curl_write(conn, sockfd, ptr, sendsize, &amount);
1058
1059 if(CURLE_OK == res) {
1060 /*
1061 * Note that we may not send the entire chunk at once, and we have a set
1062 * number of data bytes at the end of the big buffer (out of which we may
1063 * only send away a part).
1064 */
1065 /* how much of the header that was sent */
1066 size_t headlen = (size_t)amount>headersize?headersize:(size_t)amount;
1067 size_t bodylen = amount - headlen;
1068
1069 if(conn->data->set.verbose) {
1070 /* this data _may_ contain binary stuff */
1071 Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, headlen, conn);
1072 if((size_t)amount > headlen) {
1073 /* there was body data sent beyond the initial header part, pass that
1074 on to the debug callback too */
1075 Curl_debug(conn->data, CURLINFO_DATA_OUT,
1076 ptr+headlen, bodylen, conn);
1077 }
1078 }
1079 if(bodylen)
1080 /* since we sent a piece of the body here, up the byte counter for it
1081 accordingly */
1082 http->writebytecount += bodylen;
1083
1084 *bytes_written += amount;
1085
1086 if(http) {
1087 if((size_t)amount != size) {
1088 /* The whole request could not be sent in one system call. We must
1089 queue it up and send it later when we get the chance. We must not
1090 loop here and wait until it might work again. */
1091
1092 size -= amount;
1093
1094 ptr = in->buffer + amount;
1095
1096 /* backup the currently set pointers */
1097 http->backup.fread_func = conn->fread_func;
1098 http->backup.fread_in = conn->fread_in;
1099 http->backup.postdata = http->postdata;
1100 http->backup.postsize = http->postsize;
1101
1102 /* set the new pointers for the request-sending */
1103 conn->fread_func = (curl_read_callback)readmoredata;
1104 conn->fread_in = (void *)conn;
1105 http->postdata = ptr;
1106 http->postsize = (curl_off_t)size;
1107
1108 http->send_buffer = in;
1109 http->sending = HTTPSEND_REQUEST;
1110
1111 return CURLE_OK;
1112 }
1113 http->sending = HTTPSEND_BODY;
1114 /* the full buffer was sent, clean up and return */
1115 }
1116 else {
1117 if((size_t)amount != size)
1118 /* We have no continue-send mechanism now, fail. This can only happen
1119 when this function is used from the CONNECT sending function. We
1120 currently (stupidly) assume that the whole request is always sent
1121 away in the first single chunk.
1122
1123 This needs FIXing.
1124 */
1125 return CURLE_SEND_ERROR;
1126 else
1127 conn->writechannel_inuse = FALSE;
1128 }
1129 }
1130 if(in->buffer)
1131 free(in->buffer);
1132 free(in);
1133
1134 return res;
1135 }
1136
1137
1138 /*
1139 * add_bufferf() add the formatted input to the buffer.
1140 */
1141 static
add_bufferf(send_buffer * in,const char * fmt,...)1142 CURLcode add_bufferf(send_buffer *in, const char *fmt, ...)
1143 {
1144 char *s;
1145 va_list ap;
1146 va_start(ap, fmt);
1147 s = vaprintf(fmt, ap); /* this allocs a new string to append */
1148 va_end(ap);
1149
1150 if(s) {
1151 CURLcode result = add_buffer(in, s, strlen(s));
1152 free(s);
1153 return result;
1154 }
1155 /* If we failed, we cleanup the whole buffer and return error */
1156 if(in->buffer)
1157 free(in->buffer);
1158 free(in);
1159 return CURLE_OUT_OF_MEMORY;
1160 }
1161
1162 /*
1163 * add_buffer() appends a memory chunk to the existing buffer
1164 */
1165 static
add_buffer(send_buffer * in,const void * inptr,size_t size)1166 CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size)
1167 {
1168 char *new_rb;
1169 size_t new_size;
1170
1171 if(~size < in->size_used) {
1172 /* If resulting used size of send buffer would wrap size_t, cleanup
1173 the whole buffer and return error. Otherwise the required buffer
1174 size will fit into a single allocatable memory chunk */
1175 Curl_safefree(in->buffer);
1176 free(in);
1177 return CURLE_OUT_OF_MEMORY;
1178 }
1179
1180 if(!in->buffer ||
1181 ((in->size_used + size) > (in->size_max - 1))) {
1182
1183 /* If current buffer size isn't enough to hold the result, use a
1184 buffer size that doubles the required size. If this new size
1185 would wrap size_t, then just use the largest possible one */
1186
1187 if((size > (size_t)-1/2) || (in->size_used > (size_t)-1/2) ||
1188 (~(size*2) < (in->size_used*2)))
1189 new_size = (size_t)-1;
1190 else
1191 new_size = (in->size_used+size)*2;
1192
1193 if(in->buffer)
1194 /* we have a buffer, enlarge the existing one */
1195 new_rb = realloc(in->buffer, new_size);
1196 else
1197 /* create a new buffer */
1198 new_rb = malloc(new_size);
1199
1200 if(!new_rb) {
1201 /* If we failed, we cleanup the whole buffer and return error */
1202 Curl_safefree(in->buffer);
1203 free(in);
1204 return CURLE_OUT_OF_MEMORY;
1205 }
1206
1207 in->buffer = new_rb;
1208 in->size_max = new_size;
1209 }
1210 memcpy(&in->buffer[in->size_used], inptr, size);
1211
1212 in->size_used += size;
1213
1214 return CURLE_OK;
1215 }
1216
1217 /* end of the add_buffer functions */
1218 /* ------------------------------------------------------------------------- */
1219
1220 /*
1221 * Curl_compareheader()
1222 *
1223 * Returns TRUE if 'headerline' contains the 'header' with given 'content'.
1224 * Pass headers WITH the colon.
1225 */
1226 bool
Curl_compareheader(const char * headerline,const char * header,const char * content)1227 Curl_compareheader(const char *headerline, /* line to check */
1228 const char *header, /* header keyword _with_ colon */
1229 const char *content) /* content string to find */
1230 {
1231 /* RFC2616, section 4.2 says: "Each header field consists of a name followed
1232 * by a colon (":") and the field value. Field names are case-insensitive.
1233 * The field value MAY be preceded by any amount of LWS, though a single SP
1234 * is preferred." */
1235
1236 size_t hlen = strlen(header);
1237 size_t clen;
1238 size_t len;
1239 const char *start;
1240 const char *end;
1241
1242 if(!Curl_raw_nequal(headerline, header, hlen))
1243 return FALSE; /* doesn't start with header */
1244
1245 /* pass the header */
1246 start = &headerline[hlen];
1247
1248 /* pass all white spaces */
1249 while(*start && ISSPACE(*start))
1250 start++;
1251
1252 /* find the end of the header line */
1253 end = strchr(start, '\r'); /* lines end with CRLF */
1254 if(!end) {
1255 /* in case there's a non-standard compliant line here */
1256 end = strchr(start, '\n');
1257
1258 if(!end)
1259 /* hm, there's no line ending here, use the zero byte! */
1260 end = strchr(start, '\0');
1261 }
1262
1263 len = end-start; /* length of the content part of the input line */
1264 clen = strlen(content); /* length of the word to find */
1265
1266 /* find the content string in the rest of the line */
1267 for(;len>=clen;len--, start++) {
1268 if(Curl_raw_nequal(start, content, clen))
1269 return TRUE; /* match! */
1270 }
1271
1272 return FALSE; /* no match */
1273 }
1274
1275 #ifndef CURL_DISABLE_PROXY
1276 /*
1277 * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
1278 * function will issue the necessary commands to get a seamless tunnel through
1279 * this proxy. After that, the socket can be used just as a normal socket.
1280 *
1281 * This badly needs to be rewritten. CONNECT should be sent and dealt with
1282 * like any ordinary HTTP request, and not specially crafted like this. This
1283 * function only remains here like this for now since the rewrite is a bit too
1284 * much work to do at the moment.
1285 *
1286 * This function is BLOCKING which is nasty for all multi interface using apps.
1287 */
1288
Curl_proxyCONNECT(struct connectdata * conn,int sockindex,const char * hostname,unsigned short remote_port)1289 CURLcode Curl_proxyCONNECT(struct connectdata *conn,
1290 int sockindex,
1291 const char *hostname,
1292 unsigned short remote_port)
1293 {
1294 int subversion=0;
1295 struct SessionHandle *data=conn->data;
1296 struct SingleRequest *k = &data->req;
1297 CURLcode result;
1298 int res;
1299 long timeout =
1300 data->set.timeout?data->set.timeout:PROXY_TIMEOUT; /* in milliseconds */
1301 curl_socket_t tunnelsocket = conn->sock[sockindex];
1302 curl_off_t cl=0;
1303 bool closeConnection = FALSE;
1304 bool chunked_encoding = FALSE;
1305 long check;
1306
1307 #define SELECT_OK 0
1308 #define SELECT_ERROR 1
1309 #define SELECT_TIMEOUT 2
1310 int error = SELECT_OK;
1311
1312 conn->bits.proxy_connect_closed = FALSE;
1313
1314 do {
1315 if(!conn->bits.tunnel_connecting) { /* BEGIN CONNECT PHASE */
1316 char *host_port;
1317 send_buffer *req_buffer;
1318
1319 infof(data, "Establish HTTP proxy tunnel to %s:%d\n",
1320 hostname, remote_port);
1321
1322 if(data->req.newurl) {
1323 /* This only happens if we've looped here due to authentication
1324 reasons, and we don't really use the newly cloned URL here
1325 then. Just free() it. */
1326 free(data->req.newurl);
1327 data->req.newurl = NULL;
1328 }
1329
1330 /* initialize a dynamic send-buffer */
1331 req_buffer = add_buffer_init();
1332
1333 if(!req_buffer)
1334 return CURLE_OUT_OF_MEMORY;
1335
1336 host_port = aprintf("%s:%d", hostname, remote_port);
1337 if(!host_port) {
1338 free(req_buffer);
1339 return CURLE_OUT_OF_MEMORY;
1340 }
1341
1342 /* Setup the proxy-authorization header, if any */
1343 result = http_output_auth(conn, "CONNECT", host_port, TRUE);
1344
1345 if(CURLE_OK == result) {
1346 char *host=(char *)"";
1347 const char *proxyconn="";
1348 const char *useragent="";
1349 const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ?
1350 "1.0" : "1.1";
1351
1352 if(!checkheaders(data, "Host:")) {
1353 host = aprintf("Host: %s\r\n", host_port);
1354 if(!host) {
1355 free(req_buffer);
1356 free(host_port);
1357 return CURLE_OUT_OF_MEMORY;
1358 }
1359 }
1360 if(!checkheaders(data, "Proxy-Connection:"))
1361 proxyconn = "Proxy-Connection: Keep-Alive\r\n";
1362
1363 if(!checkheaders(data, "User-Agent:") &&
1364 data->set.str[STRING_USERAGENT])
1365 useragent = conn->allocptr.uagent;
1366
1367 /* Send the connect request to the proxy */
1368 /* BLOCKING */
1369 result =
1370 add_bufferf(req_buffer,
1371 "CONNECT %s:%d HTTP/%s\r\n"
1372 "%s" /* Host: */
1373 "%s" /* Proxy-Authorization */
1374 "%s" /* User-Agent */
1375 "%s", /* Proxy-Connection */
1376 hostname, remote_port, http,
1377 host,
1378 conn->allocptr.proxyuserpwd?
1379 conn->allocptr.proxyuserpwd:"",
1380 useragent,
1381 proxyconn);
1382
1383 if(host && *host)
1384 free(host);
1385
1386 if(CURLE_OK == result)
1387 result = add_custom_headers(conn, req_buffer);
1388
1389 if(CURLE_OK == result)
1390 /* CRLF terminate the request */
1391 result = add_bufferf(req_buffer, "\r\n");
1392
1393 if(CURLE_OK == result) {
1394 /* Now send off the request */
1395 result = add_buffer_send(req_buffer, conn,
1396 &data->info.request_size, 0, sockindex);
1397 }
1398 req_buffer = NULL;
1399 if(result)
1400 failf(data, "Failed sending CONNECT to proxy");
1401 }
1402 free(host_port);
1403 Curl_safefree(req_buffer);
1404 if(result)
1405 return result;
1406
1407 conn->bits.tunnel_connecting = TRUE;
1408 } /* END CONNECT PHASE */
1409
1410 /* now we've issued the CONNECT and we're waiting to hear back -
1411 we try not to block here in multi-mode because that might be a LONG
1412 wait if the proxy cannot connect-through to the remote host. */
1413
1414 /* if timeout is requested, find out how much remaining time we have */
1415 check = timeout - /* timeout time */
1416 Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
1417 if(check <=0 ) {
1418 failf(data, "Proxy CONNECT aborted due to timeout");
1419 error = SELECT_TIMEOUT; /* already too little time */
1420 break;
1421 }
1422
1423 /* if we're in multi-mode and we would block, return instead for a retry */
1424 if(Curl_if_multi == data->state.used_interface) {
1425 if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0))
1426 /* return so we'll be called again polling-style */
1427 return CURLE_OK;
1428 else {
1429 DEBUGF(infof(data,
1430 "Multi mode finished polling for response from "
1431 "proxy CONNECT."));
1432 }
1433 }
1434 else {
1435 DEBUGF(infof(data, "Easy mode waiting for response from proxy CONNECT."));
1436 }
1437
1438 /* at this point, either:
1439 1) we're in easy-mode and so it's okay to block waiting for a CONNECT
1440 response
1441 2) we're in multi-mode and we didn't block - it's either an error or we
1442 now have some data waiting.
1443 In any case, the tunnel_connecting phase is over. */
1444 conn->bits.tunnel_connecting = FALSE;
1445
1446 { /* BEGIN NEGOTIATION PHASE */
1447 size_t nread; /* total size read */
1448 int perline; /* count bytes per line */
1449 int keepon=TRUE;
1450 ssize_t gotbytes;
1451 char *ptr;
1452 char *line_start;
1453
1454 ptr=data->state.buffer;
1455 line_start = ptr;
1456
1457 nread=0;
1458 perline=0;
1459 keepon=TRUE;
1460
1461 while((nread<BUFSIZE) && (keepon && !error)) {
1462
1463 /* if timeout is requested, find out how much remaining time we have */
1464 check = timeout - /* timeout time */
1465 Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
1466 if(check <= 0) {
1467 failf(data, "Proxy CONNECT aborted due to timeout");
1468 error = SELECT_TIMEOUT; /* already too little time */
1469 break;
1470 }
1471
1472 /* loop every second at least, less if the timeout is near */
1473 switch (Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD,
1474 check<1000L?(int)check:1000)) {
1475 case -1: /* select() error, stop reading */
1476 error = SELECT_ERROR;
1477 failf(data, "Proxy CONNECT aborted due to select/poll error");
1478 break;
1479 case 0: /* timeout */
1480 break;
1481 default:
1482 DEBUGASSERT(ptr+BUFSIZE-nread <= data->state.buffer+BUFSIZE+1);
1483 res = Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes);
1484 if(res< 0)
1485 /* EWOULDBLOCK */
1486 continue; /* go loop yourself */
1487 else if(res)
1488 keepon = FALSE;
1489 else if(gotbytes <= 0) {
1490 keepon = FALSE;
1491 if(data->set.proxyauth && data->state.authproxy.avail) {
1492 /* proxy auth was requested and there was proxy auth available,
1493 then deem this as "mere" proxy disconnect */
1494 conn->bits.proxy_connect_closed = TRUE;
1495 }
1496 else {
1497 error = SELECT_ERROR;
1498 failf(data, "Proxy CONNECT aborted");
1499 }
1500 }
1501 else {
1502 /*
1503 * We got a whole chunk of data, which can be anything from one
1504 * byte to a set of lines and possibly just a piece of the last
1505 * line.
1506 */
1507 int i;
1508
1509 nread += gotbytes;
1510
1511 if(keepon > TRUE) {
1512 /* This means we are currently ignoring a response-body */
1513
1514 nread = 0; /* make next read start over in the read buffer */
1515 ptr=data->state.buffer;
1516 if(cl) {
1517 /* A Content-Length based body: simply count down the counter
1518 and make sure to break out of the loop when we're done! */
1519 cl -= gotbytes;
1520 if(cl<=0) {
1521 keepon = FALSE;
1522 break;
1523 }
1524 }
1525 else {
1526 /* chunked-encoded body, so we need to do the chunked dance
1527 properly to know when the end of the body is reached */
1528 CHUNKcode r;
1529 ssize_t tookcareof=0;
1530
1531 /* now parse the chunked piece of data so that we can
1532 properly tell when the stream ends */
1533 r = Curl_httpchunk_read(conn, ptr, gotbytes, &tookcareof);
1534 if(r == CHUNKE_STOP) {
1535 /* we're done reading chunks! */
1536 infof(data, "chunk reading DONE\n");
1537 keepon = FALSE;
1538 }
1539 else
1540 infof(data, "Read %d bytes of chunk, continue\n",
1541 tookcareof);
1542 }
1543 }
1544 else
1545 for(i = 0; i < gotbytes; ptr++, i++) {
1546 perline++; /* amount of bytes in this line so far */
1547 if(*ptr=='\n') {
1548 char letter;
1549 int writetype;
1550
1551 /* output debug if that is requested */
1552 if(data->set.verbose)
1553 Curl_debug(data, CURLINFO_HEADER_IN,
1554 line_start, (size_t)perline, conn);
1555
1556 /* send the header to the callback */
1557 writetype = CLIENTWRITE_HEADER;
1558 if(data->set.include_header)
1559 writetype |= CLIENTWRITE_BODY;
1560
1561 result = Curl_client_write(conn, writetype, line_start,
1562 perline);
1563 if(result)
1564 return result;
1565
1566 /* Newlines are CRLF, so the CR is ignored as the line isn't
1567 really terminated until the LF comes. Treat a following CR
1568 as end-of-headers as well.*/
1569
1570 if(('\r' == line_start[0]) ||
1571 ('\n' == line_start[0])) {
1572 /* end of response-headers from the proxy */
1573 nread = 0; /* make next read start over in the read
1574 buffer */
1575 ptr=data->state.buffer;
1576 if((407 == k->httpcode) && !data->state.authproblem) {
1577 /* If we get a 407 response code with content length
1578 when we have no auth problem, we must ignore the
1579 whole response-body */
1580 keepon = 2;
1581
1582 if(cl) {
1583
1584 infof(data, "Ignore %" FORMAT_OFF_T
1585 " bytes of response-body\n", cl);
1586 /* remove the remaining chunk of what we already
1587 read */
1588 cl -= (gotbytes - i);
1589
1590 if(cl<=0)
1591 /* if the whole thing was already read, we are done!
1592 */
1593 keepon=FALSE;
1594 }
1595 else if(chunked_encoding) {
1596 CHUNKcode r;
1597 /* We set ignorebody true here since the chunked
1598 decoder function will acknowledge that. Pay
1599 attention so that this is cleared again when this
1600 function returns! */
1601 k->ignorebody = TRUE;
1602 infof(data, "%d bytes of chunk left\n", gotbytes-i);
1603
1604 if(line_start[1] == '\n') {
1605 /* this can only be a LF if the letter at index 0
1606 was a CR */
1607 line_start++;
1608 i++;
1609 }
1610
1611 /* now parse the chunked piece of data so that we can
1612 properly tell when the stream ends */
1613 r = Curl_httpchunk_read(conn, line_start+1,
1614 gotbytes -i, &gotbytes);
1615 if(r == CHUNKE_STOP) {
1616 /* we're done reading chunks! */
1617 infof(data, "chunk reading DONE\n");
1618 keepon = FALSE;
1619 }
1620 else
1621 infof(data, "Read %d bytes of chunk, continue\n",
1622 gotbytes);
1623 }
1624 else {
1625 /* without content-length or chunked encoding, we
1626 can't keep the connection alive since the close is
1627 the end signal so we bail out at once instead */
1628 keepon=FALSE;
1629 }
1630 }
1631 else
1632 keepon = FALSE;
1633 break; /* breaks out of for-loop, not switch() */
1634 }
1635
1636 /* keep a backup of the position we are about to blank */
1637 letter = line_start[perline];
1638 line_start[perline]=0; /* zero terminate the buffer */
1639 if((checkprefix("WWW-Authenticate:", line_start) &&
1640 (401 == k->httpcode)) ||
1641 (checkprefix("Proxy-authenticate:", line_start) &&
1642 (407 == k->httpcode))) {
1643 result = Curl_http_input_auth(conn, k->httpcode,
1644 line_start);
1645 if(result)
1646 return result;
1647 }
1648 else if(checkprefix("Content-Length:", line_start)) {
1649 cl = curlx_strtoofft(line_start + strlen("Content-Length:"),
1650 NULL, 10);
1651 }
1652 else if(Curl_compareheader(line_start,
1653 "Connection:", "close"))
1654 closeConnection = TRUE;
1655 else if(Curl_compareheader(line_start,
1656 "Transfer-Encoding:", "chunked")) {
1657 infof(data, "CONNECT responded chunked\n");
1658 chunked_encoding = TRUE;
1659 /* init our chunky engine */
1660 Curl_httpchunk_init(conn);
1661 }
1662 else if(Curl_compareheader(line_start,
1663 "Proxy-Connection:", "close"))
1664 closeConnection = TRUE;
1665 else if(2 == sscanf(line_start, "HTTP/1.%d %d",
1666 &subversion,
1667 &k->httpcode)) {
1668 /* store the HTTP code from the proxy */
1669 data->info.httpproxycode = k->httpcode;
1670 }
1671 /* put back the letter we blanked out before */
1672 line_start[perline]= letter;
1673
1674 perline=0; /* line starts over here */
1675 line_start = ptr+1; /* this skips the zero byte we wrote */
1676 }
1677 }
1678 }
1679 break;
1680 } /* switch */
1681 if(Curl_pgrsUpdate(conn))
1682 return CURLE_ABORTED_BY_CALLBACK;
1683 } /* while there's buffer left and loop is requested */
1684
1685 if(error)
1686 return CURLE_RECV_ERROR;
1687
1688 if(data->info.httpproxycode != 200) {
1689 /* Deal with the possibly already received authenticate
1690 headers. 'newurl' is set to a new URL if we must loop. */
1691 result = Curl_http_auth_act(conn);
1692 if(result)
1693 return result;
1694
1695 if(conn->bits.close)
1696 /* the connection has been marked for closure, most likely in the
1697 Curl_http_auth_act() function and thus we can kill it at once
1698 below
1699 */
1700 closeConnection = TRUE;
1701 }
1702
1703 if(closeConnection && data->req.newurl) {
1704 /* Connection closed by server. Don't use it anymore */
1705 sclose(conn->sock[sockindex]);
1706 conn->sock[sockindex] = CURL_SOCKET_BAD;
1707 break;
1708 }
1709 } /* END NEGOTIATION PHASE */
1710 } while(data->req.newurl);
1711
1712 if(200 != data->req.httpcode) {
1713 failf(data, "Received HTTP code %d from proxy after CONNECT",
1714 data->req.httpcode);
1715
1716 if(closeConnection && data->req.newurl)
1717 conn->bits.proxy_connect_closed = TRUE;
1718
1719 return CURLE_RECV_ERROR;
1720 }
1721
1722 /* If a proxy-authorization header was used for the proxy, then we should
1723 make sure that it isn't accidentally used for the document request
1724 after we've connected. So let's free and clear it here. */
1725 Curl_safefree(conn->allocptr.proxyuserpwd);
1726 conn->allocptr.proxyuserpwd = NULL;
1727
1728 data->state.authproxy.done = TRUE;
1729
1730 infof (data, "Proxy replied OK to CONNECT request\n");
1731 data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */
1732 return CURLE_OK;
1733 }
1734 #endif /* CURL_DISABLE_PROXY */
1735
1736 /*
1737 * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
1738 * the generic Curl_connect().
1739 */
Curl_http_connect(struct connectdata * conn,bool * done)1740 CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
1741 {
1742 struct SessionHandle *data;
1743 CURLcode result;
1744
1745 data=conn->data;
1746
1747 /* We default to persistent connections. We set this already in this connect
1748 function to make the re-use checks properly be able to check this bit. */
1749 conn->bits.close = FALSE;
1750
1751 #ifndef CURL_DISABLE_PROXY
1752 /* If we are not using a proxy and we want a secure connection, perform SSL
1753 * initialization & connection now. If using a proxy with https, then we
1754 * must tell the proxy to CONNECT to the host we want to talk to. Only
1755 * after the connect has occurred, can we start talking SSL
1756 */
1757 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1758
1759 /* either SSL over proxy, or explicitly asked for */
1760 result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
1761 conn->host.name,
1762 conn->remote_port);
1763 if(CURLE_OK != result)
1764 return result;
1765 }
1766
1767 if(conn->bits.tunnel_connecting) {
1768 /* nothing else to do except wait right now - we're not done here. */
1769 return CURLE_OK;
1770 }
1771 #endif /* CURL_DISABLE_PROXY */
1772
1773 if(!data->state.this_is_a_follow) {
1774 /* this is not a followed location, get the original host name */
1775 if(data->state.first_host)
1776 /* Free to avoid leaking memory on multiple requests*/
1777 free(data->state.first_host);
1778
1779 data->state.first_host = strdup(conn->host.name);
1780 if(!data->state.first_host)
1781 return CURLE_OUT_OF_MEMORY;
1782 }
1783
1784 if(conn->protocol & PROT_HTTPS) {
1785 /* perform SSL initialization */
1786 if(data->state.used_interface == Curl_if_multi) {
1787 result = https_connecting(conn, done);
1788 if(result)
1789 return result;
1790 }
1791 else {
1792 /* BLOCKING */
1793 result = Curl_ssl_connect(conn, FIRSTSOCKET);
1794 if(result)
1795 return result;
1796 *done = TRUE;
1797 }
1798 }
1799 else {
1800 *done = TRUE;
1801 }
1802
1803 return CURLE_OK;
1804 }
1805
1806 /* this returns the socket to wait for in the DO and DOING state for the multi
1807 interface and then we're always _sending_ a request and thus we wait for
1808 the single socket to become writable only */
http_getsock_do(struct connectdata * conn,curl_socket_t * socks,int numsocks)1809 static int http_getsock_do(struct connectdata *conn,
1810 curl_socket_t *socks,
1811 int numsocks)
1812 {
1813 /* write mode */
1814 (void)numsocks; /* unused, we trust it to be at least 1 */
1815 socks[0] = conn->sock[FIRSTSOCKET];
1816 return GETSOCK_WRITESOCK(0);
1817 }
1818
1819 #ifdef USE_SSL
https_connecting(struct connectdata * conn,bool * done)1820 static CURLcode https_connecting(struct connectdata *conn, bool *done)
1821 {
1822 CURLcode result;
1823 DEBUGASSERT((conn) && (conn->protocol & PROT_HTTPS));
1824
1825 /* perform SSL initialization for this socket */
1826 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done);
1827 if(result)
1828 conn->bits.close = TRUE; /* a failed connection is marked for closure
1829 to prevent (bad) re-use or similar */
1830 return result;
1831 }
1832 #endif
1833
1834 #ifdef USE_SSLEAY
1835 /* This function is OpenSSL-specific. It should be made to query the generic
1836 SSL layer instead. */
https_getsock(struct connectdata * conn,curl_socket_t * socks,int numsocks)1837 static int https_getsock(struct connectdata *conn,
1838 curl_socket_t *socks,
1839 int numsocks)
1840 {
1841 if(conn->protocol & PROT_HTTPS) {
1842 struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
1843
1844 if(!numsocks)
1845 return GETSOCK_BLANK;
1846
1847 if(connssl->connecting_state == ssl_connect_2_writing) {
1848 /* write mode */
1849 socks[0] = conn->sock[FIRSTSOCKET];
1850 return GETSOCK_WRITESOCK(0);
1851 }
1852 else if(connssl->connecting_state == ssl_connect_2_reading) {
1853 /* read mode */
1854 socks[0] = conn->sock[FIRSTSOCKET];
1855 return GETSOCK_READSOCK(0);
1856 }
1857 }
1858 return CURLE_OK;
1859 }
1860 #else
1861 #ifdef USE_GNUTLS
https_getsock(struct connectdata * conn,curl_socket_t * socks,int numsocks)1862 static int https_getsock(struct connectdata *conn,
1863 curl_socket_t *socks,
1864 int numsocks)
1865 {
1866 (void)conn;
1867 (void)socks;
1868 (void)numsocks;
1869 return GETSOCK_BLANK;
1870 }
1871 #else
1872 #ifdef USE_NSS
https_getsock(struct connectdata * conn,curl_socket_t * socks,int numsocks)1873 static int https_getsock(struct connectdata *conn,
1874 curl_socket_t *socks,
1875 int numsocks)
1876 {
1877 (void)conn;
1878 (void)socks;
1879 (void)numsocks;
1880 return GETSOCK_BLANK;
1881 }
1882 #else
1883 #ifdef USE_QSOSSL
https_getsock(struct connectdata * conn,curl_socket_t * socks,int numsocks)1884 static int https_getsock(struct connectdata *conn,
1885 curl_socket_t *socks,
1886 int numsocks)
1887 {
1888 (void)conn;
1889 (void)socks;
1890 (void)numsocks;
1891 return GETSOCK_BLANK;
1892 }
1893 #endif
1894 #endif
1895 #endif
1896 #endif
1897
1898 /*
1899 * Curl_http_done() gets called from Curl_done() after a single HTTP request
1900 * has been performed.
1901 */
1902
Curl_http_done(struct connectdata * conn,CURLcode status,bool premature)1903 CURLcode Curl_http_done(struct connectdata *conn,
1904 CURLcode status, bool premature)
1905 {
1906 struct SessionHandle *data = conn->data;
1907 struct HTTP *http =data->state.proto.http;
1908 (void)premature; /* not used */
1909
1910 /* set the proper values (possibly modified on POST) */
1911 conn->fread_func = data->set.fread_func; /* restore */
1912 conn->fread_in = data->set.in; /* restore */
1913 conn->seek_func = data->set.seek_func; /* restore */
1914 conn->seek_client = data->set.seek_client; /* restore */
1915
1916 if(http == NULL)
1917 return CURLE_OK;
1918
1919 if(http->send_buffer) {
1920 send_buffer *buff = http->send_buffer;
1921
1922 free(buff->buffer);
1923 free(buff);
1924 http->send_buffer = NULL; /* clear the pointer */
1925 }
1926
1927 if(HTTPREQ_POST_FORM == data->set.httpreq) {
1928 data->req.bytecount = http->readbytecount + http->writebytecount;
1929
1930 Curl_formclean(&http->sendit); /* Now free that whole lot */
1931 if(http->form.fp) {
1932 /* a file being uploaded was left opened, close it! */
1933 fclose(http->form.fp);
1934 http->form.fp = NULL;
1935 }
1936 }
1937 else if(HTTPREQ_PUT == data->set.httpreq)
1938 data->req.bytecount = http->readbytecount + http->writebytecount;
1939
1940 if(status != CURLE_OK)
1941 return (status);
1942
1943 if(!premature && /* this check is pointless when DONE is called before the
1944 entire operation is complete */
1945 !conn->bits.retry &&
1946 ((http->readbytecount +
1947 data->req.headerbytecount -
1948 data->req.deductheadercount)) <= 0) {
1949 /* If this connection isn't simply closed to be retried, AND nothing was
1950 read from the HTTP server (that counts), this can't be right so we
1951 return an error here */
1952 failf(data, "Empty reply from server");
1953 return CURLE_GOT_NOTHING;
1954 }
1955
1956 return CURLE_OK;
1957 }
1958
1959
1960 /* Determine if we should use HTTP 1.1 for this request. Reasons to avoid it
1961 are if the user specifically requested HTTP 1.0, if the server we are
1962 connected to only supports 1.0, or if any server previously contacted to
1963 handle this request only supports 1.0. */
use_http_1_1(const struct SessionHandle * data,const struct connectdata * conn)1964 static bool use_http_1_1(const struct SessionHandle *data,
1965 const struct connectdata *conn)
1966 {
1967 return (bool)((data->set.httpversion == CURL_HTTP_VERSION_1_1) ||
1968 ((data->set.httpversion != CURL_HTTP_VERSION_1_0) &&
1969 ((conn->httpversion == 11) ||
1970 ((conn->httpversion != 10) &&
1971 (data->state.httpversion != 10)))));
1972 }
1973
1974 /* check and possibly add an Expect: header */
expect100(struct SessionHandle * data,struct connectdata * conn,send_buffer * req_buffer)1975 static CURLcode expect100(struct SessionHandle *data,
1976 struct connectdata *conn,
1977 send_buffer *req_buffer)
1978 {
1979 CURLcode result = CURLE_OK;
1980 data->state.expect100header = FALSE; /* default to false unless it is set
1981 to TRUE below */
1982 if(use_http_1_1(data, conn) && !checkheaders(data, "Expect:")) {
1983 /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect:
1984 100-continue to the headers which actually speeds up post
1985 operations (as there is one packet coming back from the web
1986 server) */
1987 result = add_bufferf(req_buffer,
1988 "Expect: 100-continue\r\n");
1989 if(result == CURLE_OK)
1990 data->state.expect100header = TRUE;
1991 }
1992 return result;
1993 }
1994
add_custom_headers(struct connectdata * conn,send_buffer * req_buffer)1995 static CURLcode add_custom_headers(struct connectdata *conn,
1996 send_buffer *req_buffer)
1997 {
1998 char *ptr;
1999 struct curl_slist *headers=conn->data->set.headers;
2000
2001 while(headers) {
2002 ptr = strchr(headers->data, ':');
2003 if(ptr) {
2004 /* we require a colon for this to be a true header */
2005
2006 ptr++; /* pass the colon */
2007 while(*ptr && ISSPACE(*ptr))
2008 ptr++;
2009
2010 if(*ptr) {
2011 /* only send this if the contents was non-blank */
2012
2013 if(conn->allocptr.host &&
2014 /* a Host: header was sent already, don't pass on any custom Host:
2015 header as that will produce *two* in the same request! */
2016 checkprefix("Host:", headers->data))
2017 ;
2018 else if(conn->data->set.httpreq == HTTPREQ_POST_FORM &&
2019 /* this header (extended by formdata.c) is sent later */
2020 checkprefix("Content-Type:", headers->data))
2021 ;
2022 else {
2023 CURLcode result = add_bufferf(req_buffer, "%s\r\n", headers->data);
2024 if(result)
2025 return result;
2026 }
2027 }
2028 }
2029 headers = headers->next;
2030 }
2031 return CURLE_OK;
2032 }
2033
2034 /*
2035 * Curl_http() gets called from the generic Curl_do() function when a HTTP
2036 * request is to be performed. This creates and sends a properly constructed
2037 * HTTP request.
2038 */
Curl_http(struct connectdata * conn,bool * done)2039 CURLcode Curl_http(struct connectdata *conn, bool *done)
2040 {
2041 struct SessionHandle *data=conn->data;
2042 char *buf = data->state.buffer; /* this is a short cut to the buffer */
2043 CURLcode result=CURLE_OK;
2044 struct HTTP *http;
2045 const char *ppath = data->state.path;
2046 char ftp_typecode[sizeof(";type=?")] = "";
2047 const char *host = conn->host.name;
2048 const char *te = ""; /* transfer-encoding */
2049 const char *ptr;
2050 const char *request;
2051 Curl_HttpReq httpreq = data->set.httpreq;
2052 char *addcookies = NULL;
2053 curl_off_t included_body = 0;
2054 const char *httpstring;
2055 send_buffer *req_buffer;
2056 curl_off_t postsize; /* off_t type to be able to hold a large file size */
2057
2058
2059 /* Always consider the DO phase done after this function call, even if there
2060 may be parts of the request that is not yet sent, since we can deal with
2061 the rest of the request in the PERFORM phase. */
2062 *done = TRUE;
2063
2064 /* If there already is a protocol-specific struct allocated for this
2065 sessionhandle, deal with it */
2066 Curl_reset_reqproto(conn);
2067
2068 if(!data->state.proto.http) {
2069 /* Only allocate this struct if we don't already have it! */
2070
2071 http = calloc(sizeof(struct HTTP), 1);
2072 if(!http)
2073 return CURLE_OUT_OF_MEMORY;
2074 data->state.proto.http = http;
2075 }
2076 else
2077 http = data->state.proto.http;
2078
2079 if( (conn->protocol&(PROT_HTTP|PROT_FTP)) &&
2080 data->set.upload) {
2081 httpreq = HTTPREQ_PUT;
2082 }
2083
2084 /* Now set the 'request' pointer to the proper request string */
2085 if(data->set.str[STRING_CUSTOMREQUEST])
2086 request = data->set.str[STRING_CUSTOMREQUEST];
2087 else {
2088 if(data->set.opt_no_body)
2089 request = "HEAD";
2090 else {
2091 DEBUGASSERT((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST));
2092 switch(httpreq) {
2093 case HTTPREQ_POST:
2094 case HTTPREQ_POST_FORM:
2095 request = "POST";
2096 break;
2097 case HTTPREQ_PUT:
2098 request = "PUT";
2099 break;
2100 default: /* this should never happen */
2101 case HTTPREQ_GET:
2102 request = "GET";
2103 break;
2104 case HTTPREQ_HEAD:
2105 request = "HEAD";
2106 break;
2107 }
2108 }
2109 }
2110
2111 /* The User-Agent string might have been allocated in url.c already, because
2112 it might have been used in the proxy connect, but if we have got a header
2113 with the user-agent string specified, we erase the previously made string
2114 here. */
2115 if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
2116 free(conn->allocptr.uagent);
2117 conn->allocptr.uagent=NULL;
2118 }
2119
2120 /* setup the authentication headers */
2121 result = http_output_auth(conn, request, ppath, FALSE);
2122 if(result)
2123 return result;
2124
2125 if((data->state.authhost.multi || data->state.authproxy.multi) &&
2126 (httpreq != HTTPREQ_GET) &&
2127 (httpreq != HTTPREQ_HEAD)) {
2128 /* Auth is required and we are not authenticated yet. Make a PUT or POST
2129 with content-length zero as a "probe". */
2130 conn->bits.authneg = TRUE;
2131 }
2132 else
2133 conn->bits.authneg = FALSE;
2134
2135 Curl_safefree(conn->allocptr.ref);
2136 if(data->change.referer && !checkheaders(data, "Referer:"))
2137 conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
2138 else
2139 conn->allocptr.ref = NULL;
2140
2141 if(data->set.str[STRING_COOKIE] && !checkheaders(data, "Cookie:"))
2142 addcookies = data->set.str[STRING_COOKIE];
2143
2144 if(!checkheaders(data, "Accept-Encoding:") &&
2145 data->set.str[STRING_ENCODING]) {
2146 Curl_safefree(conn->allocptr.accept_encoding);
2147 conn->allocptr.accept_encoding =
2148 aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
2149 if(!conn->allocptr.accept_encoding)
2150 return CURLE_OUT_OF_MEMORY;
2151 }
2152
2153 ptr = checkheaders(data, "Transfer-Encoding:");
2154 if(ptr) {
2155 /* Some kind of TE is requested, check if 'chunked' is chosen */
2156 data->req.upload_chunky =
2157 Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
2158 }
2159 else {
2160 if((conn->protocol&PROT_HTTP) &&
2161 data->set.upload &&
2162 (data->set.infilesize == -1)) {
2163 if (use_http_1_1(data, conn)) {
2164 /* HTTP, upload, unknown file size and not HTTP 1.0 */
2165 data->req.upload_chunky = TRUE;
2166 } else {
2167 failf(data, "Chunky upload is not supported by HTTP 1.0");
2168 return CURLE_UPLOAD_FAILED;
2169 }
2170 }
2171 else {
2172 /* else, no chunky upload */
2173 data->req.upload_chunky = FALSE;
2174 }
2175
2176 if(data->req.upload_chunky)
2177 te = "Transfer-Encoding: chunked\r\n";
2178 }
2179
2180 Curl_safefree(conn->allocptr.host);
2181
2182 ptr = checkheaders(data, "Host:");
2183 if(ptr && (!data->state.this_is_a_follow ||
2184 Curl_raw_equal(data->state.first_host, conn->host.name))) {
2185 #if !defined(CURL_DISABLE_COOKIES)
2186 /* If we have a given custom Host: header, we extract the host name in
2187 order to possibly use it for cookie reasons later on. We only allow the
2188 custom Host: header if this is NOT a redirect, as setting Host: in the
2189 redirected request is being out on thin ice. Except if the host name
2190 is the same as the first one! */
2191 char *cookiehost = Curl_copy_header_value(ptr);
2192 if (!cookiehost)
2193 return CURLE_OUT_OF_MEMORY;
2194 if (!*cookiehost)
2195 /* ignore empty data */
2196 free(cookiehost);
2197 else {
2198 char *colon = strchr(cookiehost, ':');
2199 if (colon)
2200 *colon = 0; /* The host must not include an embedded port number */
2201 Curl_safefree(conn->allocptr.cookiehost);
2202 conn->allocptr.cookiehost = cookiehost;
2203 }
2204 #endif
2205
2206 conn->allocptr.host = NULL;
2207 }
2208 else {
2209 /* When building Host: headers, we must put the host name within
2210 [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
2211
2212 if(((conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTPS)) ||
2213 (!(conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTP)) )
2214 /* if(HTTPS on port 443) OR (non-HTTPS on port 80) then don't include
2215 the port number in the host string */
2216 conn->allocptr.host = aprintf("Host: %s%s%s\r\n",
2217 conn->bits.ipv6_ip?"[":"",
2218 host,
2219 conn->bits.ipv6_ip?"]":"");
2220 else
2221 conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n",
2222 conn->bits.ipv6_ip?"[":"",
2223 host,
2224 conn->bits.ipv6_ip?"]":"",
2225 conn->remote_port);
2226
2227 if(!conn->allocptr.host)
2228 /* without Host: we can't make a nice request */
2229 return CURLE_OUT_OF_MEMORY;
2230 }
2231
2232 #ifndef CURL_DISABLE_PROXY
2233 if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
2234 /* Using a proxy but does not tunnel through it */
2235
2236 /* The path sent to the proxy is in fact the entire URL. But if the remote
2237 host is a IDN-name, we must make sure that the request we produce only
2238 uses the encoded host name! */
2239 if(conn->host.dispname != conn->host.name) {
2240 char *url = data->change.url;
2241 ptr = strstr(url, conn->host.dispname);
2242 if(ptr) {
2243 /* This is where the display name starts in the URL, now replace this
2244 part with the encoded name. TODO: This method of replacing the host
2245 name is rather crude as I believe there's a slight risk that the
2246 user has entered a user name or password that contain the host name
2247 string. */
2248 size_t currlen = strlen(conn->host.dispname);
2249 size_t newlen = strlen(conn->host.name);
2250 size_t urllen = strlen(url);
2251
2252 char *newurl;
2253
2254 newurl = malloc(urllen + newlen - currlen + 1);
2255 if(newurl) {
2256 /* copy the part before the host name */
2257 memcpy(newurl, url, ptr - url);
2258 /* append the new host name instead of the old */
2259 memcpy(newurl + (ptr - url), conn->host.name, newlen);
2260 /* append the piece after the host name */
2261 memcpy(newurl + newlen + (ptr - url),
2262 ptr + currlen, /* copy the trailing zero byte too */
2263 urllen - (ptr-url) - currlen + 1);
2264 if(data->change.url_alloc)
2265 free(data->change.url);
2266 data->change.url = newurl;
2267 data->change.url_alloc = TRUE;
2268 }
2269 else
2270 return CURLE_OUT_OF_MEMORY;
2271 }
2272 }
2273 ppath = data->change.url;
2274 if (data->set.proxy_transfer_mode) {
2275 /* when doing ftp, append ;type=<a|i> if not present */
2276 if(checkprefix("ftp://", ppath) || checkprefix("ftps://", ppath)) {
2277 char *p = strstr(ppath, ";type=");
2278 if(p && p[6] && p[7] == 0) {
2279 switch (Curl_raw_toupper(p[6])) {
2280 case 'A':
2281 case 'D':
2282 case 'I':
2283 break;
2284 default:
2285 p = NULL;
2286 }
2287 }
2288 if(!p)
2289 snprintf(ftp_typecode, sizeof(ftp_typecode), ";type=%c",
2290 data->set.prefer_ascii ? 'a' : 'i');
2291 }
2292 }
2293 }
2294 #endif /* CURL_DISABLE_PROXY */
2295
2296 if(HTTPREQ_POST_FORM == httpreq) {
2297 /* we must build the whole darned post sequence first, so that we have
2298 a size of the whole shebang before we start to send it */
2299 result = Curl_getFormData(&http->sendit, data->set.httppost,
2300 checkheaders(data, "Content-Type:"),
2301 &http->postsize);
2302 if(CURLE_OK != result) {
2303 /* Curl_getFormData() doesn't use failf() */
2304 failf(data, "failed creating formpost data");
2305 return result;
2306 }
2307 }
2308
2309
2310 http->p_accept = checkheaders(data, "Accept:")?NULL:"Accept: */*\r\n";
2311
2312 if(( (HTTPREQ_POST == httpreq) ||
2313 (HTTPREQ_POST_FORM == httpreq) ||
2314 (HTTPREQ_PUT == httpreq) ) &&
2315 data->state.resume_from) {
2316 /**********************************************************************
2317 * Resuming upload in HTTP means that we PUT or POST and that we have
2318 * got a resume_from value set. The resume value has already created
2319 * a Range: header that will be passed along. We need to "fast forward"
2320 * the file the given number of bytes and decrease the assume upload
2321 * file size before we continue this venture in the dark lands of HTTP.
2322 *********************************************************************/
2323
2324 if(data->state.resume_from < 0 ) {
2325 /*
2326 * This is meant to get the size of the present remote-file by itself.
2327 * We don't support this now. Bail out!
2328 */
2329 data->state.resume_from = 0;
2330 }
2331
2332 if(data->state.resume_from && !data->state.this_is_a_follow) {
2333 /* do we still game? */
2334
2335 /* Now, let's read off the proper amount of bytes from the
2336 input. */
2337 if(conn->seek_func) {
2338 curl_off_t readthisamountnow = data->state.resume_from;
2339
2340 if(conn->seek_func(conn->seek_client,
2341 readthisamountnow, SEEK_SET) != 0) {
2342 failf(data, "Could not seek stream");
2343 return CURLE_READ_ERROR;
2344 }
2345 }
2346 else {
2347 curl_off_t passed=0;
2348
2349 do {
2350 size_t readthisamountnow = (size_t)(data->state.resume_from - passed);
2351 size_t actuallyread;
2352
2353 if(readthisamountnow > BUFSIZE)
2354 readthisamountnow = BUFSIZE;
2355
2356 actuallyread = data->set.fread_func(data->state.buffer, 1,
2357 (size_t)readthisamountnow,
2358 data->set.in);
2359
2360 passed += actuallyread;
2361 if(actuallyread != readthisamountnow) {
2362 failf(data, "Could only read %" FORMAT_OFF_T
2363 " bytes from the input",
2364 passed);
2365 return CURLE_READ_ERROR;
2366 }
2367 } while(passed != data->state.resume_from); /* loop until done */
2368 }
2369
2370 /* now, decrease the size of the read */
2371 if(data->set.infilesize>0) {
2372 data->set.infilesize -= data->state.resume_from;
2373
2374 if(data->set.infilesize <= 0) {
2375 failf(data, "File already completely uploaded");
2376 return CURLE_PARTIAL_FILE;
2377 }
2378 }
2379 /* we've passed, proceed as normal */
2380 }
2381 }
2382 if(data->state.use_range) {
2383 /*
2384 * A range is selected. We use different headers whether we're downloading
2385 * or uploading and we always let customized headers override our internal
2386 * ones if any such are specified.
2387 */
2388 if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
2389 !checkheaders(data, "Range:")) {
2390 /* if a line like this was already allocated, free the previous one */
2391 if(conn->allocptr.rangeline)
2392 free(conn->allocptr.rangeline);
2393 conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n",
2394 data->state.range);
2395 }
2396 else if((httpreq != HTTPREQ_GET) &&
2397 !checkheaders(data, "Content-Range:")) {
2398
2399 /* if a line like this was already allocated, free the previous one */
2400 if(conn->allocptr.rangeline)
2401 free(conn->allocptr.rangeline);
2402
2403 if(data->set.set_resume_from < 0) {
2404 /* Upload resume was asked for, but we don't know the size of the
2405 remote part so we tell the server (and act accordingly) that we
2406 upload the whole file (again) */
2407 conn->allocptr.rangeline =
2408 aprintf("Content-Range: bytes 0-%" FORMAT_OFF_T
2409 "/%" FORMAT_OFF_T "\r\n",
2410 data->set.infilesize - 1, data->set.infilesize);
2411
2412 }
2413 else if(data->state.resume_from) {
2414 /* This is because "resume" was selected */
2415 curl_off_t total_expected_size=
2416 data->state.resume_from + data->set.infilesize;
2417 conn->allocptr.rangeline =
2418 aprintf("Content-Range: bytes %s%" FORMAT_OFF_T
2419 "/%" FORMAT_OFF_T "\r\n",
2420 data->state.range, total_expected_size-1,
2421 total_expected_size);
2422 }
2423 else {
2424 /* Range was selected and then we just pass the incoming range and
2425 append total size */
2426 conn->allocptr.rangeline =
2427 aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n",
2428 data->state.range, data->set.infilesize);
2429 }
2430 if(!conn->allocptr.rangeline)
2431 return CURLE_OUT_OF_MEMORY;
2432 }
2433 }
2434
2435 /* Use 1.1 unless the user specifically asked for 1.0 or the server only
2436 supports 1.0 */
2437 httpstring= use_http_1_1(data, conn)?"1.1":"1.0";
2438
2439 /* initialize a dynamic send-buffer */
2440 req_buffer = add_buffer_init();
2441
2442 if(!req_buffer)
2443 return CURLE_OUT_OF_MEMORY;
2444
2445 /* add the main request stuff */
2446 result =
2447 add_bufferf(req_buffer,
2448 "%s " /* GET/HEAD/POST/PUT */
2449 "%s%s HTTP/%s\r\n" /* path + HTTP version */
2450 "%s" /* proxyuserpwd */
2451 "%s" /* userpwd */
2452 "%s" /* range */
2453 "%s" /* user agent */
2454 "%s" /* host */
2455 "%s" /* accept */
2456 "%s" /* accept-encoding */
2457 "%s" /* referer */
2458 "%s" /* Proxy-Connection */
2459 "%s",/* transfer-encoding */
2460
2461 request,
2462 ppath,
2463 ftp_typecode,
2464 httpstring,
2465 conn->allocptr.proxyuserpwd?
2466 conn->allocptr.proxyuserpwd:"",
2467 conn->allocptr.userpwd?conn->allocptr.userpwd:"",
2468 (data->state.use_range && conn->allocptr.rangeline)?
2469 conn->allocptr.rangeline:"",
2470 (data->set.str[STRING_USERAGENT] &&
2471 *data->set.str[STRING_USERAGENT] && conn->allocptr.uagent)?
2472 conn->allocptr.uagent:"",
2473 (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */
2474 http->p_accept?http->p_accept:"",
2475 (data->set.str[STRING_ENCODING] &&
2476 *data->set.str[STRING_ENCODING] &&
2477 conn->allocptr.accept_encoding)?
2478 conn->allocptr.accept_encoding:"",
2479 (data->change.referer && conn->allocptr.ref)?
2480 conn->allocptr.ref:"" /* Referer: <data> */,
2481 (conn->bits.httpproxy &&
2482 !conn->bits.tunnel_proxy &&
2483 !checkheaders(data, "Proxy-Connection:"))?
2484 "Proxy-Connection: Keep-Alive\r\n":"",
2485 te
2486 );
2487
2488 /*
2489 * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM
2490 * with basic and digest, it will be freed anyway by the next request
2491 */
2492
2493 Curl_safefree (conn->allocptr.userpwd);
2494 conn->allocptr.userpwd = NULL;
2495
2496 if(result)
2497 return result;
2498
2499 #if !defined(CURL_DISABLE_COOKIES)
2500 if(data->cookies || addcookies) {
2501 struct Cookie *co=NULL; /* no cookies from start */
2502 int count=0;
2503
2504 if(data->cookies) {
2505 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
2506 co = Curl_cookie_getlist(data->cookies,
2507 conn->allocptr.cookiehost?
2508 conn->allocptr.cookiehost:host,
2509 data->state.path,
2510 (bool)(conn->protocol&PROT_HTTPS?TRUE:FALSE));
2511 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
2512 }
2513 if(co) {
2514 struct Cookie *store=co;
2515 /* now loop through all cookies that matched */
2516 while(co) {
2517 if(co->value) {
2518 if(0 == count) {
2519 result = add_bufferf(req_buffer, "Cookie: ");
2520 if(result)
2521 break;
2522 }
2523 result = add_bufferf(req_buffer,
2524 "%s%s=%s", count?"; ":"",
2525 co->name, co->value);
2526 if(result)
2527 break;
2528 count++;
2529 }
2530 co = co->next; /* next cookie please */
2531 }
2532 Curl_cookie_freelist(store, FALSE); /* free the cookie list */
2533 }
2534 if(addcookies && (CURLE_OK == result)) {
2535 if(!count)
2536 result = add_bufferf(req_buffer, "Cookie: ");
2537 if(CURLE_OK == result) {
2538 result = add_bufferf(req_buffer, "%s%s",
2539 count?"; ":"",
2540 addcookies);
2541 count++;
2542 }
2543 }
2544 if(count && (CURLE_OK == result))
2545 result = add_buffer(req_buffer, "\r\n", 2);
2546
2547 if(result)
2548 return result;
2549 }
2550 #endif
2551
2552 if(data->set.timecondition) {
2553 struct tm *tm;
2554
2555 /* The If-Modified-Since header family should have their times set in
2556 * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be
2557 * represented in Greenwich Mean Time (GMT), without exception. For the
2558 * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal
2559 * Time)." (see page 20 of RFC2616).
2560 */
2561
2562 #ifdef HAVE_GMTIME_R
2563 /* thread-safe version */
2564 struct tm keeptime;
2565 tm = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
2566 #else
2567 tm = gmtime(&data->set.timevalue);
2568 #endif
2569
2570 /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
2571 snprintf(buf, BUFSIZE-1,
2572 "%s, %02d %s %4d %02d:%02d:%02d GMT",
2573 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2574 tm->tm_mday,
2575 Curl_month[tm->tm_mon],
2576 tm->tm_year + 1900,
2577 tm->tm_hour,
2578 tm->tm_min,
2579 tm->tm_sec);
2580
2581 switch(data->set.timecondition) {
2582 case CURL_TIMECOND_IFMODSINCE:
2583 default:
2584 result = add_bufferf(req_buffer,
2585 "If-Modified-Since: %s\r\n", buf);
2586 break;
2587 case CURL_TIMECOND_IFUNMODSINCE:
2588 result = add_bufferf(req_buffer,
2589 "If-Unmodified-Since: %s\r\n", buf);
2590 break;
2591 case CURL_TIMECOND_LASTMOD:
2592 result = add_bufferf(req_buffer,
2593 "Last-Modified: %s\r\n", buf);
2594 break;
2595 }
2596 if(result)
2597 return result;
2598 }
2599
2600 result = add_custom_headers(conn, req_buffer);
2601 if(result)
2602 return result;
2603
2604 http->postdata = NULL; /* nothing to post at this point */
2605 Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
2606
2607 /* If 'authdone' is FALSE, we must not set the write socket index to the
2608 Curl_transfer() call below, as we're not ready to actually upload any
2609 data yet. */
2610
2611 switch(httpreq) {
2612
2613 case HTTPREQ_POST_FORM:
2614 if(!http->sendit || conn->bits.authneg) {
2615 /* nothing to post! */
2616 result = add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
2617 if(result)
2618 return result;
2619
2620 result = add_buffer_send(req_buffer, conn,
2621 &data->info.request_size, 0, FIRSTSOCKET);
2622 if(result)
2623 failf(data, "Failed sending POST request");
2624 else
2625 /* setup variables for the upcoming transfer */
2626 result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2627 &http->readbytecount,
2628 -1, NULL);
2629 break;
2630 }
2631
2632 if(Curl_FormInit(&http->form, http->sendit)) {
2633 failf(data, "Internal HTTP POST error!");
2634 return CURLE_HTTP_POST_ERROR;
2635 }
2636
2637 /* Get the currently set callback function pointer and store that in the
2638 form struct since we might want the actual user-provided callback later
2639 on. The conn->fread_func pointer itself will be changed for the
2640 multipart case to the function that returns a multipart formatted
2641 stream. */
2642 http->form.fread_func = conn->fread_func;
2643
2644 /* Set the read function to read from the generated form data */
2645 conn->fread_func = (curl_read_callback)Curl_FormReader;
2646 conn->fread_in = &http->form;
2647
2648 http->sending = HTTPSEND_BODY;
2649
2650 if(!data->req.upload_chunky) {
2651 /* only add Content-Length if not uploading chunked */
2652 result = add_bufferf(req_buffer,
2653 "Content-Length: %" FORMAT_OFF_T "\r\n",
2654 http->postsize);
2655 if(result)
2656 return result;
2657 }
2658
2659 result = expect100(data, conn, req_buffer);
2660 if(result)
2661 return result;
2662
2663 {
2664
2665 /* Get Content-Type: line from Curl_formpostheader.
2666 */
2667 char *contentType;
2668 size_t linelength=0;
2669 contentType = Curl_formpostheader((void *)&http->form,
2670 &linelength);
2671 if(!contentType) {
2672 failf(data, "Could not get Content-Type header line!");
2673 return CURLE_HTTP_POST_ERROR;
2674 }
2675
2676 result = add_buffer(req_buffer, contentType, linelength);
2677 if(result)
2678 return result;
2679 }
2680
2681 /* make the request end in a true CRLF */
2682 result = add_buffer(req_buffer, "\r\n", 2);
2683 if(result)
2684 return result;
2685
2686 /* set upload size to the progress meter */
2687 Curl_pgrsSetUploadSize(data, http->postsize);
2688
2689 /* fire away the whole request to the server */
2690 result = add_buffer_send(req_buffer, conn,
2691 &data->info.request_size, 0, FIRSTSOCKET);
2692 if(result)
2693 failf(data, "Failed sending POST request");
2694 else
2695 /* setup variables for the upcoming transfer */
2696 result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2697 &http->readbytecount,
2698 FIRSTSOCKET,
2699 &http->writebytecount);
2700
2701 if(result) {
2702 Curl_formclean(&http->sendit); /* free that whole lot */
2703 return result;
2704 }
2705 #ifdef CURL_DOES_CONVERSIONS
2706 /* time to convert the form data... */
2707 result = Curl_formconvert(data, http->sendit);
2708 if(result) {
2709 Curl_formclean(&http->sendit); /* free that whole lot */
2710 return result;
2711 }
2712 #endif /* CURL_DOES_CONVERSIONS */
2713 break;
2714
2715 case HTTPREQ_PUT: /* Let's PUT the data to the server! */
2716
2717 if(conn->bits.authneg)
2718 postsize = 0;
2719 else
2720 postsize = data->set.infilesize;
2721
2722 if((postsize != -1) && !data->req.upload_chunky) {
2723 /* only add Content-Length if not uploading chunked */
2724 result = add_bufferf(req_buffer,
2725 "Content-Length: %" FORMAT_OFF_T "\r\n",
2726 postsize );
2727 if(result)
2728 return result;
2729 }
2730
2731 result = expect100(data, conn, req_buffer);
2732 if(result)
2733 return result;
2734
2735 result = add_buffer(req_buffer, "\r\n", 2); /* end of headers */
2736 if(result)
2737 return result;
2738
2739 /* set the upload size to the progress meter */
2740 Curl_pgrsSetUploadSize(data, postsize);
2741
2742 /* this sends the buffer and frees all the buffer resources */
2743 result = add_buffer_send(req_buffer, conn,
2744 &data->info.request_size, 0, FIRSTSOCKET);
2745 if(result)
2746 failf(data, "Failed sending PUT request");
2747 else
2748 /* prepare for transfer */
2749 result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2750 &http->readbytecount,
2751 postsize?FIRSTSOCKET:-1,
2752 postsize?&http->writebytecount:NULL);
2753 if(result)
2754 return result;
2755 break;
2756
2757 case HTTPREQ_POST:
2758 /* this is the simple POST, using x-www-form-urlencoded style */
2759
2760 if(conn->bits.authneg)
2761 postsize = 0;
2762 else {
2763 /* figure out the size of the postfields */
2764 postsize = (data->set.postfieldsize != -1)?
2765 data->set.postfieldsize:
2766 (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0);
2767 }
2768 if(!data->req.upload_chunky) {
2769 /* We only set Content-Length and allow a custom Content-Length if
2770 we don't upload data chunked, as RFC2616 forbids us to set both
2771 kinds of headers (Transfer-Encoding: chunked and Content-Length) */
2772
2773 if(!checkheaders(data, "Content-Length:")) {
2774 /* we allow replacing this header, although it isn't very wise to
2775 actually set your own */
2776 result = add_bufferf(req_buffer,
2777 "Content-Length: %" FORMAT_OFF_T"\r\n",
2778 postsize);
2779 if(result)
2780 return result;
2781 }
2782 }
2783
2784 if(!checkheaders(data, "Content-Type:")) {
2785 result = add_bufferf(req_buffer,
2786 "Content-Type: application/x-www-form-urlencoded\r\n");
2787 if(result)
2788 return result;
2789 }
2790
2791 /* For really small posts we don't use Expect: headers at all, and for
2792 the somewhat bigger ones we allow the app to disable it. Just make
2793 sure that the expect100header is always set to the preferred value
2794 here. */
2795 if(postsize > TINY_INITIAL_POST_SIZE) {
2796 result = expect100(data, conn, req_buffer);
2797 if(result)
2798 return result;
2799 }
2800 else
2801 data->state.expect100header = FALSE;
2802
2803 if(data->set.postfields) {
2804
2805 if(!data->state.expect100header &&
2806 (postsize < MAX_INITIAL_POST_SIZE)) {
2807 /* if we don't use expect: 100 AND
2808 postsize is less than MAX_INITIAL_POST_SIZE
2809
2810 then append the post data to the HTTP request header. This limit
2811 is no magic limit but only set to prevent really huge POSTs to
2812 get the data duplicated with malloc() and family. */
2813
2814 result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2815 if(result)
2816 return result;
2817
2818 if(!data->req.upload_chunky) {
2819 /* We're not sending it 'chunked', append it to the request
2820 already now to reduce the number if send() calls */
2821 result = add_buffer(req_buffer, data->set.postfields,
2822 (size_t)postsize);
2823 included_body = postsize;
2824 }
2825 else {
2826 /* Append the POST data chunky-style */
2827 result = add_bufferf(req_buffer, "%x\r\n", (int)postsize);
2828 if(CURLE_OK == result)
2829 result = add_buffer(req_buffer, data->set.postfields,
2830 (size_t)postsize);
2831 if(CURLE_OK == result)
2832 result = add_buffer(req_buffer,
2833 "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7);
2834 /* CR LF 0 CR LF CR LF */
2835 included_body = postsize + 7;
2836 }
2837 if(result)
2838 return result;
2839 }
2840 else {
2841 /* A huge POST coming up, do data separate from the request */
2842 http->postsize = postsize;
2843 http->postdata = data->set.postfields;
2844
2845 http->sending = HTTPSEND_BODY;
2846
2847 conn->fread_func = (curl_read_callback)readmoredata;
2848 conn->fread_in = (void *)conn;
2849
2850 /* set the upload size to the progress meter */
2851 Curl_pgrsSetUploadSize(data, http->postsize);
2852
2853 result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2854 if(result)
2855 return result;
2856 }
2857 }
2858 else {
2859 result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2860 if(result)
2861 return result;
2862
2863 if(data->set.postfieldsize) {
2864 /* set the upload size to the progress meter */
2865 Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
2866
2867 /* set the pointer to mark that we will send the post body using the
2868 read callback, but only if we're not in authenticate
2869 negotiation */
2870 if(!conn->bits.authneg) {
2871 http->postdata = (char *)&http->postdata;
2872 http->postsize = postsize;
2873 }
2874 }
2875 }
2876 /* issue the request */
2877 result = add_buffer_send(req_buffer, conn, &data->info.request_size,
2878 (size_t)included_body, FIRSTSOCKET);
2879
2880 if(result)
2881 failf(data, "Failed sending HTTP POST request");
2882 else
2883 result =
2884 Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2885 &http->readbytecount,
2886 http->postdata?FIRSTSOCKET:-1,
2887 http->postdata?&http->writebytecount:NULL);
2888 break;
2889
2890 default:
2891 result = add_buffer(req_buffer, "\r\n", 2);
2892 if(result)
2893 return result;
2894
2895 /* issue the request */
2896 result = add_buffer_send(req_buffer, conn,
2897 &data->info.request_size, 0, FIRSTSOCKET);
2898
2899 if(result)
2900 failf(data, "Failed sending HTTP request");
2901 else
2902 /* HTTP GET/HEAD download: */
2903 result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2904 &http->readbytecount,
2905 http->postdata?FIRSTSOCKET:-1,
2906 http->postdata?&http->writebytecount:NULL);
2907 }
2908 if(result)
2909 return result;
2910
2911 if(http->writebytecount) {
2912 /* if a request-body has been sent off, we make sure this progress is noted
2913 properly */
2914 Curl_pgrsSetUploadCounter(data, http->writebytecount);
2915 if(Curl_pgrsUpdate(conn))
2916 result = CURLE_ABORTED_BY_CALLBACK;
2917 }
2918
2919 return result;
2920 }
2921 #endif
2922