doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
http.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2004, 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.204 2004/03/14 18:15:04 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 #include <sys/types.h>
34 #include <sys/stat.h>
35 
36 #include <errno.h>
37 
38 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
39 #include <time.h>
40 #include <io.h>
41 #else
42 #ifdef HAVE_SYS_SOCKET_H
43 #include <sys/socket.h>
44 #endif
45 #ifdef HAVE_NETINET_IN_H
46 #include <netinet/in.h>
47 #endif
48 #include <sys/time.h>
49 
50 #ifdef HAVE_TIME_H
51 #ifdef TIME_WITH_SYS_TIME
52 #include <time.h>
53 #endif
54 #endif
55 
56 #ifdef HAVE_UNISTD_H
57 #include <unistd.h>
58 #endif
59 #include <netdb.h>
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 #include <sys/ioctl.h>
67 #include <signal.h>
68 
69 #ifdef HAVE_SYS_PARAM_H
70 #include <sys/param.h>
71 #endif
72 
73 #ifdef HAVE_SYS_SELECT_H
74 #include <sys/select.h>
75 #endif
76 
77 
78 #endif
79 
80 #include "urldata.h"
81 #include <curl/curl.h>
82 #include "transfer.h"
83 #include "sendf.h"
84 #include "formdata.h"
85 #include "progress.h"
86 #include "base64.h"
87 #include "cookie.h"
88 #include "strequal.h"
89 #include "ssluse.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 "http.h"
96 
97 #define _MPRINTF_REPLACE /* use our functions only */
98 #include <curl/mprintf.h>
99 
100 /* The last #include file should be: */
101 #ifdef CURLDEBUG
102 #include "memdebug.h"
103 #endif
104 
105 static CURLcode Curl_output_basic_proxy(struct connectdata *conn);
106 
107 /*
108  * This function checks the linked list of custom HTTP headers for a particular
109  * header (prefix).
110  */
111 static char *checkheaders(struct SessionHandle *data, const char *thisheader)
112 {
113  struct curl_slist *head;
114  size_t thislen = strlen(thisheader);
115 
116  for(head = data->set.headers; head; head=head->next) {
117  if(strnequal(head->data, thisheader, thislen))
118  return head->data;
119  }
120  return NULL;
121 }
122 
123 static CURLcode Curl_output_basic(struct connectdata *conn)
124 {
125  char *authorization;
126  struct SessionHandle *data=conn->data;
127 
128  sprintf(data->state.buffer, "%s:%s", conn->user, conn->passwd);
129  if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer),
130  &authorization) > 0) {
131  if(conn->allocptr.userpwd)
132  free(conn->allocptr.userpwd);
133  conn->allocptr.userpwd = aprintf( "Authorization: Basic %s\015\012",
134  authorization);
135  free(authorization);
136  }
137  else
138  return CURLE_OUT_OF_MEMORY;
139  return CURLE_OK;
140 }
141 
142 static CURLcode Curl_output_basic_proxy(struct connectdata *conn)
143 {
144  char *authorization;
145  struct SessionHandle *data=conn->data;
146 
147  sprintf(data->state.buffer, "%s:%s",
148  conn->proxyuser, conn->proxypasswd);
149  if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer),
150  &authorization) > 0) {
152  conn->allocptr.proxyuserpwd =
153  aprintf("Proxy-authorization: Basic %s\015\012", authorization);
154  free(authorization);
155  }
156  else
157  return CURLE_OUT_OF_MEMORY;
158  return CURLE_OK;
159 }
160 
161 /*
162  * Curl_http_auth_act() checks what authentication methods that are available
163  * and decides which one (if any) to use. It will set 'newurl' if an auth
164  * metod was picked.
165  */
166 
167 void Curl_http_auth_act(struct connectdata *conn)
168 {
169  struct SessionHandle *data = conn->data;
170 
171  if(data->state.authavail) {
172  /* The order of these checks is highly relevant, as this will be the order
173  of preference in case of the existance of multiple accepted types. */
176  else if(data->state.authavail & CURLAUTH_DIGEST)
178  else if(data->state.authavail & CURLAUTH_NTLM)
179  data->state.authwant = CURLAUTH_NTLM;
180  else if(data->state.authavail & CURLAUTH_BASIC)
181  data->state.authwant = CURLAUTH_BASIC;
182  else
183  data->state.authwant = CURLAUTH_NONE; /* clear it */
184 
185  if(data->state.authwant)
186  conn->newurl = strdup(data->change.url); /* clone URL */
187  data->state.authavail = CURLAUTH_NONE; /* clear it here */
188  }
189 }
190 
191 /*
192  * Setup the authentication headers for the host/proxy and the correct
193  * authentication method.
194  */
195 
196 static CURLcode http_auth_headers(struct connectdata *conn,
197  char *request,
198  char *path,
199  bool *ready) /* set TRUE when the auth phase
200  is done and ready to do the *actual*
201  request */
202 {
204  struct SessionHandle *data = conn->data;
205  char *auth=NULL;
206 
207  *ready = FALSE; /* default is no */
208 
209  if(!data->state.authstage) {
210  if(conn->bits.httpproxy && conn->bits.proxy_user_passwd)
211  Curl_http_auth_stage(data, 407);
212  else if(conn->bits.user_passwd)
213  Curl_http_auth_stage(data, 401);
214  else {
215  *ready = TRUE;
216  return CURLE_OK; /* no authentication with no user or password */
217  }
218  }
219 
220  /* To prevent the user+password to get sent to other than the original
221  host due to a location-follow, we do some weirdo checks here */
222  if(!data->state.this_is_a_follow ||
223  !data->state.auth_host ||
224  curl_strequal(data->state.auth_host, conn->hostname) ||
226 
227  /* Send proxy authentication header if needed */
228  if (data->state.authstage == 407) {
229 #ifdef USE_SSLEAY
230  if(data->state.authwant == CURLAUTH_NTLM) {
231  auth=(char *)"NTLM";
232  result = Curl_output_ntlm(conn, TRUE, ready);
233  if(result)
234  return result;
235  }
236  else
237 #endif
238  if(data->state.authwant == CURLAUTH_BASIC) {
239  /* Basic */
240  if(conn->bits.proxy_user_passwd &&
241  !checkheaders(data, "Proxy-authorization:")) {
242  auth=(char *)"Basic";
243  result = Curl_output_basic_proxy(conn);
244  if(result)
245  return result;
246  }
247  *ready = TRUE;
248  /* Switch to web authentication after proxy authentication is done */
249  Curl_http_auth_stage(data, 401);
250  }
251  infof(data, "Proxy auth using %s with user '%s'\n",
252  auth, conn->proxyuser?conn->proxyuser:"");
253  }
254  /* Send web authentication header if needed */
255  if (data->state.authstage == 401) {
256  auth = NULL;
257 #ifdef HAVE_GSSAPI
258  if((data->state.authwant == CURLAUTH_GSSNEGOTIATE) &&
259  data->state.negotiate.context &&
260  !GSS_ERROR(data->state.negotiate.status)) {
261  auth=(char *)"GSS-Negotiate";
262  result = Curl_output_negotiate(conn);
263  if (result)
264  return result;
265  *ready = TRUE;
266  }
267  else
268 #endif
269 #ifdef USE_SSLEAY
270  if(data->state.authwant == CURLAUTH_NTLM) {
271  auth=(char *)"NTLM";
272  result = Curl_output_ntlm(conn, FALSE, ready);
273  if(result)
274  return result;
275  }
276  else
277 #endif
278  {
279  if((data->state.authwant == CURLAUTH_DIGEST) &&
280  data->state.digest.nonce) {
281  auth=(char *)"Digest";
282  result = Curl_output_digest(conn,
283  (unsigned char *)request,
284  (unsigned char *)path);
285  if(result)
286  return result;
287  *ready = TRUE;
288  }
289  else if(data->state.authwant == CURLAUTH_BASIC) {/* Basic */
290  if(conn->bits.user_passwd &&
291  !checkheaders(data, "Authorization:")) {
292  auth=(char *)"Basic";
293  result = Curl_output_basic(conn);
294  if(result)
295  return result;
296  }
297  /* basic is always ready */
298  *ready = TRUE;
299  }
300  }
301  if(auth)
302  infof(data, "Server auth using %s with user '%s'\n",
303  auth, conn->user);
304  }
305  }
306  else
307  *ready = TRUE;
308 
309  return result;
310 }
311 
312 
313 /*
314  * Curl_http_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
315  * headers. They are dealt with both in the transfer.c main loop and in the
316  * proxy CONNECT loop.
317  */
318 
320  int httpcode,
321  char *header) /* pointing to the first non-space */
322 {
323  /*
324  * This resource requires authentication
325  */
326  struct SessionHandle *data = conn->data;
327 
328  long *availp;
329  char *start;
330 
331  if (httpcode == 407) {
332  start = header+strlen("Proxy-authenticate:");
333  availp = &data->info.proxyauthavail;
334  }
335  else {
336  start = header+strlen("WWW-Authenticate:");
337  availp = &data->info.httpauthavail;
338  }
339  /*
340  * Switch from proxy to web authentication and back if needed
341  */
342  if (httpcode == 407 && data->state.authstage != 407)
343  Curl_http_auth_stage(data, 407);
344 
345  else if (httpcode == 401 && data->state.authstage != 401)
346  Curl_http_auth_stage(data, 401);
347 
348  /* pass all white spaces */
349  while(*start && isspace((int)*start))
350  start++;
351 
352  /*
353  * Here we check if we want the specific single authentiction (using ==) and
354  * if we do, we initiate usage of it.
355  *
356  * If the provided authentication is wanted as one out of several accepted
357  * types (using &), we OR this authenticaion type to the authavail
358  * variable.
359  */
360 
361 #ifdef HAVE_GSSAPI
362  if (checkprefix("GSS-Negotiate", start) ||
363  checkprefix("Negotiate", start)) {
364  *availp |= CURLAUTH_GSSNEGOTIATE;
365  if(data->state.authwant == CURLAUTH_GSSNEGOTIATE) {
366  /* if exactly this is wanted, go */
367  int neg = Curl_input_negotiate(conn, start);
368  if (neg == 0)
369  conn->newurl = strdup(data->change.url);
370  }
371  else
374  }
375  else
376 #endif
377 #ifdef USE_SSLEAY
378  /* NTLM support requires the SSL crypto libs */
379  if(checkprefix("NTLM", start)) {
380  *availp |= CURLAUTH_NTLM;
381  if(data->state.authwant == CURLAUTH_NTLM) {
382  /* NTLM authentication is activated */
383  CURLntlm ntlm =
384  Curl_input_ntlm(conn, (bool)(httpcode == 407), start);
385 
386  if(CURLNTLM_BAD != ntlm)
387  conn->newurl = strdup(data->change.url); /* clone string */
388  else
389  infof(data, "Authentication problem. Ignoring this.\n");
390  }
391  else
392  if(data->state.authwant & CURLAUTH_NTLM)
393  data->state.authavail |= CURLAUTH_NTLM;
394  }
395  else
396 #endif
397  if(checkprefix("Digest", start)) {
398  *availp |= CURLAUTH_DIGEST;
399  if(data->state.authwant == CURLAUTH_DIGEST) {
400  /* Digest authentication is activated */
402 
403  if(data->state.digest.nonce)
404  infof(data, "Authentication problem. Ignoring this.\n");
405  else
406  dig = Curl_input_digest(conn, start);
407 
408  if(CURLDIGEST_FINE == dig)
409  /* We act on it. Store our new url, which happens to be
410  the same one we already use! */
411  conn->newurl = strdup(data->change.url); /* clone string */
412  }
413  else
414  if(data->state.authwant & CURLAUTH_DIGEST) {
415  /* We don't know if Digest is what we're gonna use, but we
416  call this function anyway to store the digest data that
417  is provided on this line, to skip the extra round-trip
418  we need to do otherwise. We must sure to free this
419  data! */
420  Curl_input_digest(conn, start);
422  }
423  }
424  else if(checkprefix("Basic", start)) {
425  *availp |= CURLAUTH_BASIC;
426  if((data->state.authwant == CURLAUTH_BASIC) &&
427  (httpcode == data->state.authstage)) {
428  /* We asked for Basic authentication but got a 40X back
429  anyway, which basicly means our name+password isn't
430  valid. */
431  data->state.authavail = CURLAUTH_NONE;
432  infof(data, "Authentication problem. Ignoring this.\n");
433  }
434  else if(data->state.authwant & CURLAUTH_BASIC) {
435  data->state.authavail |= CURLAUTH_BASIC;
436  }
437  }
438  return CURLE_OK;
439 }
440 
441 
442 /* fread() emulation to provide POST and/or request data */
443 static size_t readmoredata(char *buffer,
444  size_t size,
445  size_t nitems,
446  void *userp)
447 {
448  struct connectdata *conn = (struct connectdata *)userp;
449  struct HTTP *http = conn->proto.http;
450  size_t fullsize = size * nitems;
451 
452  if(0 == http->postsize)
453  /* nothing to return */
454  return 0;
455 
456  /* make sure that a HTTP request is never sent away chunked! */
458 
459  if(http->postsize <= (curl_off_t)fullsize) {
460  memcpy(buffer, http->postdata, (size_t)http->postsize);
461  fullsize = (size_t)http->postsize;
462 
463  if(http->backup.postsize) {
464  /* move backup data into focus and continue on that */
465  http->postdata = http->backup.postdata;
466  http->postsize = http->backup.postsize;
467  conn->fread = http->backup.fread;
468  conn->fread_in = http->backup.fread_in;
469 
470  http->sending++; /* move one step up */
471 
472  http->backup.postsize=0;
473  }
474  else
475  http->postsize = 0;
476 
477  return fullsize;
478  }
479 
480  memcpy(buffer, http->postdata, fullsize);
481  http->postdata += fullsize;
482  http->postsize -= fullsize;
483 
484  return fullsize;
485 }
486 
487 /* ------------------------------------------------------------------------- */
488 /*
489  * The add_buffer series of functions are used to build one large memory chunk
490  * from repeated function invokes. Used so that the entire HTTP request can
491  * be sent in one go.
492  */
493 
494 struct send_buffer {
495  char *buffer;
496  size_t size_max;
497  size_t size_used;
498 };
499 typedef struct send_buffer send_buffer;
500 
501 static CURLcode
502  add_buffer(send_buffer *in, const void *inptr, size_t size);
503 
504 /*
505  * add_buffer_init() returns a fine buffer struct
506  */
507 static
508 send_buffer *add_buffer_init(void)
509 {
510  send_buffer *blonk;
511  blonk=(send_buffer *)malloc(sizeof(send_buffer));
512  if(blonk) {
513  memset(blonk, 0, sizeof(send_buffer));
514  return blonk;
515  }
516  return NULL; /* failed, go home */
517 }
518 
519 /*
520  * add_buffer_send() sends a buffer and frees all associated memory.
521  */
522 static
523 CURLcode add_buffer_send(send_buffer *in,
524  struct connectdata *conn,
525  long *bytes_written) /* add the number of sent
526  bytes to this counter */
527 {
528  ssize_t amount;
529  CURLcode res;
530  char *ptr;
531  size_t size;
532  struct HTTP *http = conn->proto.http;
533  size_t sendsize;
534  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
535 
536  /* The looping below is required since we use non-blocking sockets, but due
537  to the circumstances we will just loop and try again and again etc */
538 
539  ptr = in->buffer;
540  size = in->size_used;
541 
542  if(conn->protocol & PROT_HTTPS) {
543  /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
544  when we speak HTTPS, as if only a fraction of it is sent now, this data
545  needs to fit into the normal read-callback buffer later on and that
546  buffer is using this size.
547  */
548 
549  sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:size;
550 
551  /* OpenSSL is very picky and we must send the SAME buffer pointer to the
552  library when we attempt to re-send this buffer. Sending the same data
553  is not enough, we must use the exact same address. For this reason, we
554  must copy the data to the uploadbuffer first, since that is the buffer
555  we will be using if this send is retried later.
556  */
557  memcpy(conn->data->state.uploadbuffer, ptr, sendsize);
558  ptr = conn->data->state.uploadbuffer;
559  }
560  else
561  sendsize = size;
562 
563  res = Curl_write(conn, sockfd, ptr, sendsize, &amount);
564 
565  if(CURLE_OK == res) {
566 
567  if(conn->data->set.verbose)
568  /* this data _may_ contain binary stuff */
569  Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, amount);
570 
571  *bytes_written += amount;
572 
573  if((size_t)amount != size) {
574  /* The whole request could not be sent in one system call. We must queue
575  it up and send it later when we get the chance. We must not loop here
576  and wait until it might work again. */
577 
578  size -= amount;
579 
580  ptr = in->buffer + amount;
581 
582  /* backup the currently set pointers */
583  http->backup.fread = conn->fread;
584  http->backup.fread_in = conn->fread_in;
585  http->backup.postdata = http->postdata;
586  http->backup.postsize = http->postsize;
587 
588  /* set the new pointers for the request-sending */
589  conn->fread = (curl_read_callback)readmoredata;
590  conn->fread_in = (void *)conn;
591  http->postdata = ptr;
592  http->postsize = size;
593 
594  http->send_buffer = in;
595  http->sending = HTTPSEND_REQUEST;
596 
597  return CURLE_OK;
598  }
599  http->sending = HTTPSEND_BODY;
600  /* the full buffer was sent, clean up and return */
601  }
602  if(in->buffer)
603  free(in->buffer);
604  free(in);
605 
606  return res;
607 }
608 
609 
610 /*
611  * add_bufferf() builds a buffer from the formatted input
612  */
613 static
614 CURLcode add_bufferf(send_buffer *in, const char *fmt, ...)
615 {
616  char *s;
617  va_list ap;
618  va_start(ap, fmt);
619  s = vaprintf(fmt, ap); /* this allocs a new string to append */
620  va_end(ap);
621 
622  if(s) {
623  CURLcode result = add_buffer(in, s, strlen(s));
624  free(s);
625  if(CURLE_OK == result)
626  return CURLE_OK;
627  }
628  /* If we failed, we cleanup the whole buffer and return error */
629  if(in->buffer)
630  free(in->buffer);
631  free(in);
632  return CURLE_OUT_OF_MEMORY;
633 }
634 
635 /*
636  * add_buffer() appends a memory chunk to the existing one
637  */
638 static
639 CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size)
640 {
641  char *new_rb;
642  size_t new_size;
643 
644  if(!in->buffer ||
645  ((in->size_used + size) > (in->size_max - 1))) {
646  new_size = (in->size_used+size)*2;
647  if(in->buffer)
648  /* we have a buffer, enlarge the existing one */
649  new_rb = (char *)realloc(in->buffer, new_size);
650  else
651  /* create a new buffer */
652  new_rb = (char *)malloc(new_size);
653 
654  if(!new_rb)
655  return CURLE_OUT_OF_MEMORY;
656 
657  in->buffer = new_rb;
658  in->size_max = new_size;
659  }
660  memcpy(&in->buffer[in->size_used], inptr, size);
661 
662  in->size_used += size;
663 
664  return CURLE_OK;
665 }
666 
667 /* end of the add_buffer functions */
668 /* ------------------------------------------------------------------------- */
669 
670 /*
671  * Curl_compareheader()
672  *
673  * Returns TRUE if 'headerline' contains the 'header' with given 'content'.
674  * Pass headers WITH the colon.
675  */
676 bool
677 Curl_compareheader(char *headerline, /* line to check */
678  const char *header, /* header keyword _with_ colon */
679  const char *content) /* content string to find */
680 {
681  /* RFC2616, section 4.2 says: "Each header field consists of a name followed
682  * by a colon (":") and the field value. Field names are case-insensitive.
683  * The field value MAY be preceded by any amount of LWS, though a single SP
684  * is preferred." */
685 
686  size_t hlen = strlen(header);
687  size_t clen;
688  size_t len;
689  char *start;
690  char *end;
691 
692  if(!strnequal(headerline, header, hlen))
693  return FALSE; /* doesn't start with header */
694 
695  /* pass the header */
696  start = &headerline[hlen];
697 
698  /* pass all white spaces */
699  while(*start && isspace((int)*start))
700  start++;
701 
702  /* find the end of the header line */
703  end = strchr(start, '\r'); /* lines end with CRLF */
704  if(!end) {
705  /* in case there's a non-standard compliant line here */
706  end = strchr(start, '\n');
707 
708  if(!end)
709  /* hm, there's no line ending here, use the zero byte! */
710  end = strchr(start, '\0');
711  }
712 
713  len = end-start; /* length of the content part of the input line */
714  clen = strlen(content); /* length of the word to find */
715 
716  /* find the content string in the rest of the line */
717  for(;len>=clen;len--, start++) {
718  if(strnequal(start, content, clen))
719  return TRUE; /* match! */
720  }
721 
722  return FALSE; /* no match */
723 }
724 
725 /*
726  * ConnectHTTPProxyTunnel() requires that we're connected to a HTTP proxy. This
727  * function will issue the necessary commands to get a seamless tunnel through
728  * this proxy. After that, the socket can be used just as a normal socket.
729  */
730 
732  int sockindex,
733  char *hostname,
734  int remote_port)
735 {
736  int httpcode=0;
737  int subversion=0;
738  struct SessionHandle *data=conn->data;
740  int res;
741 
742  size_t nread; /* total size read */
743  int perline; /* count bytes per line */
744  bool keepon=TRUE;
745  ssize_t gotbytes;
746  char *ptr;
747  long timeout = 3600; /* default timeout in seconds */
748  struct timeval interval;
749  fd_set rkeepfd;
750  fd_set readfd;
751  char *line_start;
752  char *host_port;
753  curl_socket_t tunnelsocket = conn->sock[sockindex];
754 
755 #define SELECT_OK 0
756 #define SELECT_ERROR 1
757 #define SELECT_TIMEOUT 2
758  int error = SELECT_OK;
759 
760  infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
761 
762  do {
763  bool auth; /* we don't really have to know when the auth phase is done,
764  but this variable will be set to true then */
765 
766  if(conn->newurl) {
767  /* This only happens if we've looped here due to authentication reasons,
768  and we don't really use the newly cloned URL here then. Just free()
769  it. */
770  free(conn->newurl);
771  conn->newurl = NULL;
772  }
773 
774  host_port = aprintf("%s:%d", hostname, remote_port);
775  if(!host_port)
776  return CURLE_OUT_OF_MEMORY;
777 
778  /* Setup the proxy-authorization header, if any */
779  result = http_auth_headers(conn, (char *)"CONNECT", host_port, &auth);
780  if(CURLE_OK == result) {
781 
782  /* OK, now send the connect request to the proxy */
783  result =
784  Curl_sendf(tunnelsocket, conn,
785  "CONNECT %s:%d HTTP/1.0\015\012"
786  "%s"
787  "%s"
788  "\r\n",
789  hostname, remote_port,
790  conn->bits.proxy_user_passwd?
791  conn->allocptr.proxyuserpwd:"",
792  data->set.useragent?conn->allocptr.uagent:""
793  );
794  if(result)
795  failf(data, "Failed sending CONNECT to proxy");
796  }
797  free(host_port);
798  if(result)
799  return result;
800 
801  FD_ZERO (&readfd); /* clear it */
802  FD_SET (tunnelsocket, &readfd); /* read socket */
803 
804  /* get this in a backup variable to be able to restore it on each lap in
805  the select() loop */
806  rkeepfd = readfd;
807 
808  ptr=data->state.buffer;
809  line_start = ptr;
810 
811  nread=0;
812  perline=0;
813  keepon=TRUE;
814 
815  while((nread<BUFSIZE) && (keepon && !error)) {
816  readfd = rkeepfd; /* set every lap */
817  interval.tv_sec = 1; /* timeout each second and check the timeout */
818  interval.tv_usec = 0;
819 
820  if(data->set.timeout) {
821  /* if timeout is requested, find out how much remaining time we have */
822  timeout = data->set.timeout - /* timeout time */
823  Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
824  if(timeout <=0 ) {
825  failf(data, "Proxy connection aborted due to timeout");
826  error = SELECT_TIMEOUT; /* already too little time */
827  break;
828  }
829  }
830 
831  switch (select (tunnelsocket+1, &readfd, NULL, NULL, &interval)) {
832  case -1: /* select() error, stop reading */
833  error = SELECT_ERROR;
834  failf(data, "Proxy CONNECT aborted due to select() error");
835  break;
836  case 0: /* timeout */
837  break;
838  default:
839  /*
840  * This code previously didn't use the kerberos sec_read() code
841  * to read, but when we use Curl_read() it may do so. Do confirm
842  * that this is still ok and then remove this comment!
843  */
844  res= Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes);
845  if(res< 0)
846  /* EWOULDBLOCK */
847  continue; /* go loop yourself */
848  else if(res)
849  keepon = FALSE;
850  else if(gotbytes <= 0) {
851  keepon = FALSE;
852  error = SELECT_ERROR;
853  failf(data, "Proxy CONNECT aborted");
854  }
855  else {
856  /*
857  * We got a whole chunk of data, which can be anything from one byte
858  * to a set of lines and possibly just a piece of the last line.
859  *
860  * TODO: To make this code work less error-prone, we need to make
861  * sure that we read and create full lines before we compare them,
862  * as there is really nothing that stops the proxy from delivering
863  * the response lines in multiple parts, each part consisting of
864  * only a little piece of the line(s). */
865  int i;
866 
867  nread += gotbytes;
868  for(i = 0; i < gotbytes; ptr++, i++) {
869  perline++; /* amount of bytes in this line so far */
870  if(*ptr=='\n') {
871  char letter;
872  int writetype;
873 
874  /* output debug output if that is requested */
875  if(data->set.verbose)
876  Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline);
877 
878  /* send the header to the callback */
879  writetype = CLIENTWRITE_HEADER;
880  if(data->set.http_include_header)
881  writetype |= CLIENTWRITE_BODY;
882 
883  result = Curl_client_write(data, writetype, line_start, perline);
884  if(result)
885  return result;
886 
887  /* Newlines are CRLF, so the CR is ignored as the line isn't
888  really terminated until the LF comes. Treat a following CR
889  as end-of-headers as well.*/
890 
891  if(('\r' == line_start[0]) ||
892  ('\n' == line_start[0])) {
893  /* end of response-headers from the proxy */
894  keepon=FALSE;
895  break; /* breaks out of for-loop, not switch() */
896  }
897 
898  /* keep a backup of the position we are about to blank */
899  letter = line_start[perline];
900  line_start[perline]=0; /* zero terminate the buffer */
901  if((checkprefix("WWW-Authenticate:", line_start) &&
902  (401 == httpcode)) ||
903  (checkprefix("Proxy-authenticate:", line_start) &&
904  (407 == httpcode))) {
905  result = Curl_http_auth(conn, httpcode, line_start);
906  if(result)
907  return result;
908  }
909  else if(2 == sscanf(line_start, "HTTP/1.%d %d",
910  &subversion,
911  &httpcode)) {
912  /* store the HTTP code */
913  data->info.httpproxycode = httpcode;
914  }
915  /* put back the letter we blanked out before */
916  line_start[perline]= letter;
917 
918  perline=0; /* line starts over here */
919  line_start = ptr+1; /* this skips the zero byte we wrote */
920  }
921  }
922  }
923  break;
924  } /* switch */
925  } /* while there's buffer left and loop is requested */
926 
927  if(error)
928  return CURLE_RECV_ERROR;
929 
930  /* Deal with the possibly already received authenticate headers. 'newurl'
931  is set to a new URL if we must loop. */
932  Curl_http_auth_act(conn);
933 
934  } while(conn->newurl);
935 
936  if(200 != httpcode) {
937  failf(data, "Received HTTP code %d from proxy after CONNECT", httpcode);
938  return CURLE_RECV_ERROR;
939  }
940 
941  /* If a proxy-authorization header was used for the proxy, then we should
942  make sure that it isn't accidentally used for the document request
943  after we've connected. So let's free and clear it here. */
945  conn->allocptr.proxyuserpwd = NULL;
946 
947  Curl_http_auth_stage(data, 401); /* move on to the host auth */
948 
949  infof (data, "Proxy replied OK to CONNECT request\n");
950  return CURLE_OK;
951 }
952 
953 /*
954  * HTTP stuff to do at connect-time.
955  */
957 {
958  struct SessionHandle *data;
960 
961  data=conn->data;
962 
963  /* If we are not using a proxy and we want a secure connection,
964  * perform SSL initialization & connection now.
965  * If using a proxy with https, then we must tell the proxy to CONNECT
966  * us to the host we want to talk to. Only after the connect
967  * has occured, can we start talking SSL
968  */
969 
970  if(conn->bits.httpproxy &&
971  ((conn->protocol & PROT_HTTPS) || data->set.tunnel_thru_httpproxy)) {
972 
973  /* either HTTPS over proxy, OR explicitly asked for a tunnel */
975  conn->hostname, conn->remote_port);
976  if(CURLE_OK != result)
977  return result;
978  }
979 
980  if(conn->protocol & PROT_HTTPS) {
981  /* now, perform the SSL initialization for this socket */
982  result = Curl_SSLConnect(conn, FIRSTSOCKET);
983  if(result)
984  return result;
985  }
986 
987  if(conn->bits.user_passwd && !data->state.this_is_a_follow) {
988  /* Authorization: is requested, this is not a followed location, get the
989  original host name */
990  if (data->state.auth_host)
991  /* Free to avoid leaking memory on multiple requests*/
992  free(data->state.auth_host);
993 
994  data->state.auth_host = strdup(conn->hostname);
995  }
996 
997  return CURLE_OK;
998 }
999 
1001 {
1002  struct SessionHandle *data;
1003  struct HTTP *http;
1004 
1005  data=conn->data;
1006  http=conn->proto.http;
1007 
1008  /* set the proper values (possibly modified on POST) */
1009  conn->fread = data->set.fread; /* restore */
1010  conn->fread_in = data->set.in; /* restore */
1011 
1012  if (http == NULL)
1013  return CURLE_OK;
1014 
1015  if(http->send_buffer) {
1016  send_buffer *buff = http->send_buffer;
1017 
1018  free(buff->buffer);
1019  free(buff);
1020  http->send_buffer = NULL; /* cleaer the pointer */
1021  }
1022 
1023  if(HTTPREQ_POST_FORM == data->set.httpreq) {
1024  conn->bytecount = http->readbytecount + http->writebytecount;
1025 
1026  Curl_formclean(http->sendit); /* Now free that whole lot */
1027  }
1028  else if(HTTPREQ_PUT == data->set.httpreq)
1029  conn->bytecount = http->readbytecount + http->writebytecount;
1030 
1031  if(!conn->bits.retry &&
1032  !(http->readbytecount + conn->headerbytecount)) {
1033  /* If this connection isn't simply closed to be retried, AND nothing was
1034  read from the HTTP server, this can't be right so we return an error
1035  here */
1036  failf(data, "Empty reply from server");
1037  return CURLE_GOT_NOTHING;
1038  }
1039 
1040  return CURLE_OK;
1041 }
1042 
1044  int stage)
1045 {
1046  curlassert((stage == 401) || (stage == 407));
1047 
1048  /* We set none, one or more bits for which authentication types we accept
1049  for this stage. */
1050  data->state.authwant = (stage == 401)?
1051  data->set.httpauth:data->set.proxyauth;
1052 
1053  data->state.authstage = stage;
1054  data->state.authavail = CURLAUTH_NONE; /* no type available yet */
1055 }
1056 
1058 {
1059  struct SessionHandle *data=conn->data;
1060  char *buf = data->state.buffer; /* this is a short cut to the buffer */
1061  CURLcode result=CURLE_OK;
1062  struct HTTP *http;
1063  struct Cookie *co=NULL; /* no cookies from start */
1064  char *ppath = conn->ppath; /* three previous function arguments */
1065  char *host = conn->name;
1066  const char *te = ""; /* tranfer-encoding */
1067  char *ptr;
1068  char *request;
1069  bool authdone=TRUE; /* if the authentication phase is done */
1070 
1071  if(!conn->proto.http) {
1072  /* Only allocate this struct if we don't already have it! */
1073 
1074  http = (struct HTTP *)malloc(sizeof(struct HTTP));
1075  if(!http)
1076  return CURLE_OUT_OF_MEMORY;
1077  memset(http, 0, sizeof(struct HTTP));
1078  conn->proto.http = http;
1079  }
1080  else
1081  http = conn->proto.http;
1082 
1083  /* We default to persistant connections */
1084  conn->bits.close = FALSE;
1085 
1086  if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) &&
1087  data->set.upload) {
1088  data->set.httpreq = HTTPREQ_PUT;
1089  }
1090 
1091  request = data->set.customrequest?
1092  data->set.customrequest:
1093  (data->set.no_body?(char *)"HEAD":
1094  ((HTTPREQ_POST == data->set.httpreq) ||
1095  (HTTPREQ_POST_FORM == data->set.httpreq))?(char *)"POST":
1096  (HTTPREQ_PUT == data->set.httpreq)?(char *)"PUT":(char *)"GET");
1097 
1098  /* The User-Agent string has been built in url.c already, because it might
1099  have been used in the proxy connect, but if we have got a header with
1100  the user-agent string specified, we erase the previously made string
1101  here. */
1102  if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
1103  free(conn->allocptr.uagent);
1104  conn->allocptr.uagent=NULL;
1105  }
1106 
1107  /* setup the authentication headers */
1108  result = http_auth_headers(conn, request, ppath, &authdone);
1109  if(result)
1110  return result;
1111 
1112  Curl_safefree(conn->allocptr.ref);
1113  if(data->change.referer && !checkheaders(data, "Referer:"))
1114  conn->allocptr.ref = aprintf("Referer: %s\015\012", data->change.referer);
1115  else
1116  conn->allocptr.ref = NULL;
1117 
1118  Curl_safefree(conn->allocptr.cookie);
1119  if(data->set.cookie && !checkheaders(data, "Cookie:"))
1120  conn->allocptr.cookie = aprintf("Cookie: %s\015\012", data->set.cookie);
1121  else
1122  conn->allocptr.cookie = NULL;
1123 
1124  if(!conn->bits.upload_chunky && (data->set.httpreq != HTTPREQ_GET)) {
1125  /* not a chunky transfer yet, but data is to be sent */
1126  ptr = checkheaders(data, "Transfer-Encoding:");
1127  if(ptr) {
1128  /* Some kind of TE is requested, check if 'chunked' is chosen */
1129  conn->bits.upload_chunky =
1130  Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
1131  te = "";
1132  }
1133  }
1134  else if(conn->bits.upload_chunky) {
1135  /* RFC2616 section 4.4:
1136  Messages MUST NOT include both a Content-Length header field and a
1137  non-identity transfer-coding. If the message does include a non-
1138  identity transfer-coding, the Content-Length MUST be ignored. */
1139 
1140  if(!checkheaders(data, "Transfer-Encoding:")) {
1141  te = "Transfer-Encoding: chunked\r\n";
1142  }
1143  else {
1144  te = "";
1145  conn->bits.upload_chunky = FALSE; /* transfer-encoding was disabled,
1146  so don't chunkify this! */
1147  }
1148  }
1149 
1150  ptr = checkheaders(data, "Host:");
1151  if(ptr && !data->state.this_is_a_follow) {
1152  /* If we have a given custom Host: header, we extract the host name in
1153  order to possibly use it for cookie reasons later on. We only allow the
1154  custom Host: header if this is NOT a redirect, as setting Host: in the
1155  redirected request is being out on thin ice. */
1156  char *start = ptr+strlen("Host:");
1157  while(*start && isspace((int)*start ))
1158  start++;
1159  ptr = start; /* start host-scanning here */
1160 
1161  /* scan through the string to find the end (space or colon) */
1162  while(*ptr && !isspace((int)*ptr) && !(':'==*ptr))
1163  ptr++;
1164 
1165  if(ptr != start) {
1166  size_t len=ptr-start;
1167  conn->allocptr.cookiehost = malloc(len+1);
1168  if(!conn->allocptr.cookiehost)
1169  return CURLE_OUT_OF_MEMORY;
1170  memcpy(conn->allocptr.cookiehost, start, len);
1171  conn->allocptr.cookiehost[len]=0;
1172  }
1173  }
1174  else {
1175  Curl_safefree(conn->allocptr.host);
1176 
1177  /* When building Host: headers, we must put the host name within
1178  [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
1179 
1180  if(((conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTPS)) ||
1181  (!(conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTP)) )
1182  /* If (HTTPS on port 443) OR (non-HTTPS on port 80) then don't include
1183  the port number in the host string */
1184  conn->allocptr.host = aprintf("Host: %s%s%s\r\n",
1185  conn->bits.ipv6_ip?"[":"",
1186  host,
1187  conn->bits.ipv6_ip?"]":"");
1188  else
1189  conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n",
1190  conn->bits.ipv6_ip?"[":"",
1191  host,
1192  conn->bits.ipv6_ip?"]":"",
1193  conn->remote_port);
1194 
1195  if(!conn->allocptr.host)
1196  /* without Host: we can't make a nice request */
1197  return CURLE_OUT_OF_MEMORY;
1198  }
1199 
1200  if(data->cookies) {
1202  co = Curl_cookie_getlist(data->cookies,
1203  conn->allocptr.cookiehost?
1204  conn->allocptr.cookiehost:host, ppath,
1205  (bool)(conn->protocol&PROT_HTTPS?TRUE:FALSE));
1207  }
1208 
1209  if (conn->bits.httpproxy &&
1210  !data->set.tunnel_thru_httpproxy &&
1211  !(conn->protocol&PROT_HTTPS)) {
1212  /* The path sent to the proxy is in fact the entire URL */
1213  ppath = data->change.url;
1214  }
1215  if(HTTPREQ_POST_FORM == data->set.httpreq) {
1216  /* we must build the whole darned post sequence first, so that we have
1217  a size of the whole shebang before we start to send it */
1218  result = Curl_getFormData(&http->sendit, data->set.httppost,
1219  &http->postsize);
1220  if(CURLE_OK != result) {
1221  /* Curl_getFormData() doesn't use failf() */
1222  failf(data, "failed creating formpost data");
1223  return result;
1224  }
1225  }
1226 
1227 
1228  if(!checkheaders(data, "Pragma:"))
1229  http->p_pragma = "Pragma: no-cache\r\n";
1230 
1231  if(!checkheaders(data, "Accept:"))
1232  http->p_accept = "Accept: */*\r\n";
1233 
1234  if(( (HTTPREQ_POST == data->set.httpreq) ||
1235  (HTTPREQ_POST_FORM == data->set.httpreq) ||
1236  (HTTPREQ_PUT == data->set.httpreq) ) &&
1237  conn->resume_from) {
1238  /**********************************************************************
1239  * Resuming upload in HTTP means that we PUT or POST and that we have
1240  * got a resume_from value set. The resume value has already created
1241  * a Range: header that will be passed along. We need to "fast forward"
1242  * the file the given number of bytes and decrease the assume upload
1243  * file size before we continue this venture in the dark lands of HTTP.
1244  *********************************************************************/
1245 
1246  if(conn->resume_from < 0 ) {
1247  /*
1248  * This is meant to get the size of the present remote-file by itself.
1249  * We don't support this now. Bail out!
1250  */
1251  conn->resume_from = 0;
1252  }
1253 
1254  if(conn->resume_from) {
1255  /* do we still game? */
1256  curl_off_t passed=0;
1257 
1258  /* Now, let's read off the proper amount of bytes from the
1259  input. If we knew it was a proper file we could've just
1260  fseek()ed but we only have a stream here */
1261  do {
1262  size_t readthisamountnow = (size_t)(conn->resume_from - passed);
1263  size_t actuallyread;
1264 
1265  if(readthisamountnow > BUFSIZE)
1266  readthisamountnow = BUFSIZE;
1267 
1268  actuallyread =
1269  data->set.fread(data->state.buffer, 1, (size_t)readthisamountnow,
1270  data->set.in);
1271 
1272  passed += actuallyread;
1273  if(actuallyread != readthisamountnow) {
1274  failf(data, "Could only read %" FORMAT_OFF_T
1275  " bytes from the input",
1276  passed);
1277  return CURLE_READ_ERROR;
1278  }
1279  } while(passed != conn->resume_from); /* loop until done */
1280 
1281  /* now, decrease the size of the read */
1282  if(data->set.infilesize>0) {
1283  data->set.infilesize -= conn->resume_from;
1284 
1285  if(data->set.infilesize <= 0) {
1286  failf(data, "File already completely uploaded");
1287  return CURLE_PARTIAL_FILE;
1288  }
1289  }
1290  /* we've passed, proceed as normal */
1291  }
1292  }
1293  if(conn->bits.use_range) {
1294  /*
1295  * A range is selected. We use different headers whether we're downloading
1296  * or uploading and we always let customized headers override our internal
1297  * ones if any such are specified.
1298  */
1299  if((data->set.httpreq == HTTPREQ_GET) &&
1300  !checkheaders(data, "Range:")) {
1301  /* if a line like this was already allocated, free the previous one */
1302  if(conn->allocptr.rangeline)
1303  free(conn->allocptr.rangeline);
1304  conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", conn->range);
1305  }
1306  else if((data->set.httpreq != HTTPREQ_GET) &&
1307  !checkheaders(data, "Content-Range:")) {
1308 
1309  if(conn->resume_from) {
1310  /* This is because "resume" was selected */
1311  curl_off_t total_expected_size=
1312  conn->resume_from + data->set.infilesize;
1313  conn->allocptr.rangeline =
1314  aprintf("Content-Range: bytes %s%" FORMAT_OFF_T
1315  "/%" FORMAT_OFF_T "\r\n",
1316  conn->range, total_expected_size-1,
1317  total_expected_size);
1318  }
1319  else {
1320  /* Range was selected and then we just pass the incoming range and
1321  append total size */
1322  conn->allocptr.rangeline =
1323  aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n",
1324  conn->range, data->set.infilesize);
1325  }
1326  }
1327  }
1328 
1329  {
1330  /* Use 1.1 unless the use specificly asked for 1.0 */
1331  const char *httpstring=
1332  data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1";
1333 
1334  send_buffer *req_buffer;
1335  struct curl_slist *headers=data->set.headers;
1336  curl_off_t postsize; /* off_t type to be able to hold a large file size */
1337 
1338  /* initialize a dynamic send-buffer */
1339  req_buffer = add_buffer_init();
1340 
1341  if(!req_buffer)
1342  return CURLE_OUT_OF_MEMORY;
1343 
1344  /* add the main request stuff */
1345  result =
1346  add_bufferf(req_buffer,
1347  "%s " /* GET/HEAD/POST/PUT */
1348  "%s HTTP/%s\r\n" /* path + HTTP version */
1349  "%s" /* proxyuserpwd */
1350  "%s" /* userpwd */
1351  "%s" /* range */
1352  "%s" /* user agent */
1353  "%s" /* cookie */
1354  "%s" /* host */
1355  "%s" /* pragma */
1356  "%s" /* accept */
1357  "%s" /* accept-encoding */
1358  "%s" /* referer */
1359  "%s",/* transfer-encoding */
1360 
1361  request,
1362  ppath,
1363  httpstring,
1364  (conn->bits.httpproxy && conn->allocptr.proxyuserpwd)?
1365  conn->allocptr.proxyuserpwd:"",
1366  conn->allocptr.userpwd?conn->allocptr.userpwd:"",
1367  (conn->bits.use_range && conn->allocptr.rangeline)?
1368  conn->allocptr.rangeline:"",
1369  (data->set.useragent && *data->set.useragent && conn->allocptr.uagent)?
1370  conn->allocptr.uagent:"",
1371  (conn->allocptr.cookie?conn->allocptr.cookie:""), /* Cookie: <data> */
1372  (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */
1373  http->p_pragma?http->p_pragma:"",
1374  http->p_accept?http->p_accept:"",
1375  (data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)?
1376  conn->allocptr.accept_encoding:"", /* 08/28/02 jhrg */
1377  (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: <data> <CRLF> */,
1378  te
1379  );
1380 
1381  if(result)
1382  return result;
1383 
1384  if(co) {
1385  int count=0;
1386  struct Cookie *store=co;
1387  /* now loop through all cookies that matched */
1388  while(co) {
1389  if(co->value) {
1390  if(0 == count) {
1391  add_bufferf(req_buffer, "Cookie: ");
1392  }
1393  add_bufferf(req_buffer,
1394  "%s%s=%s", count?"; ":"", co->name, co->value);
1395  count++;
1396  }
1397  co = co->next; /* next cookie please */
1398  }
1399  if(count) {
1400  add_buffer(req_buffer, "\r\n", 2);
1401  }
1402  Curl_cookie_freelist(store); /* free the cookie list */
1403  co=NULL;
1404  }
1405 
1406  if(data->set.timecondition) {
1407  struct tm *thistime;
1408 
1409  /* Phil Karn (Fri, 13 Apr 2001) pointed out that the If-Modified-Since
1410  * header family should have their times set in GMT as RFC2616 defines:
1411  * "All HTTP date/time stamps MUST be represented in Greenwich Mean Time
1412  * (GMT), without exception. For the purposes of HTTP, GMT is exactly
1413  * equal to UTC (Coordinated Universal Time)." (see page 20 of RFC2616).
1414  */
1415 
1416 #ifdef HAVE_GMTIME_R
1417  /* thread-safe version */
1418  struct tm keeptime;
1419  thistime = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
1420 #else
1421  thistime = gmtime(&data->set.timevalue);
1422 #endif
1423 
1424 #ifdef HAVE_STRFTIME
1425  /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
1426  strftime(buf, BUFSIZE-1, "%a, %d %b %Y %H:%M:%S GMT", thistime);
1427 #else
1428  /* TODO: Right, we *could* write a replacement here */
1429  strcpy(buf, "no strftime() support");
1430 #endif
1431  switch(data->set.timecondition) {
1433  default:
1434  add_bufferf(req_buffer,
1435  "If-Modified-Since: %s\r\n", buf);
1436  break;
1438  add_bufferf(req_buffer,
1439  "If-Unmodified-Since: %s\r\n", buf);
1440  break;
1441  case CURL_TIMECOND_LASTMOD:
1442  add_bufferf(req_buffer,
1443  "Last-Modified: %s\r\n", buf);
1444  break;
1445  }
1446  }
1447 
1448  while(headers) {
1449  ptr = strchr(headers->data, ':');
1450  if(ptr) {
1451  /* we require a colon for this to be a true header */
1452 
1453  ptr++; /* pass the colon */
1454  while(*ptr && isspace((int)*ptr))
1455  ptr++;
1456 
1457  if(*ptr) {
1458  /* only send this if the contents was non-blank */
1459 
1460  add_bufferf(req_buffer, "%s\r\n", headers->data);
1461  }
1462  }
1463  headers = headers->next;
1464  }
1465 
1466  http->postdata = NULL; /* nothing to post at this point */
1467  Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
1468 
1469  /* If 'authdone' is still FALSE, we must not set the write socket index to
1470  the Curl_transfer() call below, as we're not ready to actually upload
1471  any data yet. */
1472 
1473  switch(data->set.httpreq) {
1474 
1475  case HTTPREQ_POST_FORM:
1476  if(Curl_FormInit(&http->form, http->sendit)) {
1477  failf(data, "Internal HTTP POST error!");
1478  return CURLE_HTTP_POST_ERROR;
1479  }
1480 
1481  /* set the read function to read from the generated form data */
1483  conn->fread_in = &http->form;
1484 
1485  http->sending = HTTPSEND_BODY;
1486 
1487  if(!conn->bits.upload_chunky)
1488  /* only add Content-Length if not uploading chunked */
1489  add_bufferf(req_buffer,
1490  "Content-Length: %" FORMAT_OFF_T "\r\n", http->postsize);
1491 
1492  if(!checkheaders(data, "Expect:")) {
1493  /* if not disabled explicitly we add a Expect: 100-continue
1494  to the headers which actually speeds up post operations (as
1495  there is one packet coming back from the web server) */
1496  add_bufferf(req_buffer,
1497  "Expect: 100-continue\r\n");
1498  data->set.expect100header = TRUE;
1499  }
1500 
1501  if(!checkheaders(data, "Content-Type:")) {
1502  /* Get Content-Type: line from Curl_FormReadOneLine, which happens
1503  to always be the first line. We can know this for sure since
1504  we always build the formpost linked list the same way!
1505 
1506  The Content-Type header line also contains the MIME boundary
1507  string etc why disabling this header is likely to not make things
1508  work, but we support it anyway.
1509  */
1510  char contentType[256];
1511  size_t linelength=0;
1512  linelength = Curl_FormReadOneLine(contentType,
1513  sizeof(contentType),
1514  1,
1515  (FILE *)&http->form);
1516  if(!linelength) {
1517  failf(data, "Could not get Content-Type header line!");
1518  return CURLE_HTTP_POST_ERROR;
1519  }
1520  add_buffer(req_buffer, contentType, linelength);
1521  }
1522 
1523  /* make the request end in a true CRLF */
1524  add_buffer(req_buffer, "\r\n", 2);
1525 
1526  /* set upload size to the progress meter */
1527  Curl_pgrsSetUploadSize(data, http->postsize);
1528 
1529  /* fire away the whole request to the server */
1530  result = add_buffer_send(req_buffer, conn,
1531  &data->info.request_size);
1532  if(result)
1533  failf(data, "Failed sending POST request");
1534  else
1535  /* setup variables for the upcoming transfer */
1536  result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
1537  &http->readbytecount,
1538  authdone?FIRSTSOCKET:-1,
1539  authdone?&http->writebytecount:NULL);
1540  if(result) {
1541  Curl_formclean(http->sendit); /* free that whole lot */
1542  return result;
1543  }
1544  break;
1545 
1546  case HTTPREQ_PUT: /* Let's PUT the data to the server! */
1547 
1548  if((data->set.infilesize>0) && !conn->bits.upload_chunky)
1549  /* only add Content-Length if not uploading chunked */
1550  add_bufferf(req_buffer,
1551  "Content-Length: %" FORMAT_OFF_T "\r\n", /* size */
1552  data->set.infilesize );
1553 
1554  if(!checkheaders(data, "Expect:")) {
1555  /* if not disabled explicitly we add a Expect: 100-continue
1556  to the headers which actually speeds up post operations (as
1557  there is one packet coming back from the web server) */
1558  add_bufferf(req_buffer,
1559  "Expect: 100-continue\r\n");
1560  data->set.expect100header = TRUE;
1561  }
1562 
1563  add_buffer(req_buffer, "\r\n", 2); /* end of headers */
1564 
1565  /* set the upload size to the progress meter */
1566  Curl_pgrsSetUploadSize(data, data->set.infilesize);
1567 
1568  /* this sends the buffer and frees all the buffer resources */
1569  result = add_buffer_send(req_buffer, conn,
1570  &data->info.request_size);
1571  if(result)
1572  failf(data, "Failed sending POST request");
1573  else
1574  /* prepare for transfer */
1575  result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
1576  &http->readbytecount,
1577  authdone?FIRSTSOCKET:-1,
1578  authdone?&http->writebytecount:NULL);
1579  if(result)
1580  return result;
1581  break;
1582 
1583  case HTTPREQ_POST:
1584  /* this is the simple POST, using x-www-form-urlencoded style */
1585 
1586  /* store the size of the postfields */
1587  postsize = data->set.postfieldsize?
1588  data->set.postfieldsize:
1589  (data->set.postfields?(curl_off_t)strlen(data->set.postfields):0);
1590 
1591  if(!conn->bits.upload_chunky) {
1592  /* We only set Content-Length and allow a custom Content-Length if
1593  we don't upload data chunked, as RFC2616 forbids us to set both
1594  kinds of headers (Transfer-Encoding: chunked and Content-Length) */
1595 
1596  if(!checkheaders(data, "Content-Length:"))
1597  /* we allow replacing this header, although it isn't very wise to
1598  actually set your own */
1599  add_bufferf(req_buffer, "Content-Length: %" FORMAT_OFF_T"\r\n",
1600  postsize);
1601  }
1602 
1603  if(!checkheaders(data, "Content-Type:"))
1604  add_bufferf(req_buffer,
1605  "Content-Type: application/x-www-form-urlencoded\r\n");
1606 
1607  if(data->set.postfields) {
1608 
1609  if(authdone && (postsize < (100*1024))) {
1610  /* If we're not done with the authentication phase, we don't expect
1611  to actually send off any data yet. Hence, we delay the sending of
1612  the body until we receive that friendly 100-continue response */
1613 
1614  /* The post data is less than 100K, then append it to the header.
1615  This limit is no magic limit but only set to prevent really huge
1616  POSTs to get the data duplicated with malloc() and family. */
1617 
1618  add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
1619 
1620  if(!conn->bits.upload_chunky)
1621  /* We're not sending it 'chunked', append it to the request
1622  already now to reduce the number if send() calls */
1623  add_buffer(req_buffer, data->set.postfields, (size_t)postsize);
1624  else {
1625  /* Append the POST data chunky-style */
1626  add_bufferf(req_buffer, "%x\r\n", (int)postsize);
1627  add_buffer(req_buffer, data->set.postfields, (size_t)postsize);
1628  add_buffer(req_buffer, "\r\n0\r\n\r\n", 7); /* end of a chunked
1629  transfer stream */
1630  }
1631  }
1632  else {
1633  /* A huge POST coming up, do data separate from the request */
1634  http->postsize = postsize;
1635  http->postdata = data->set.postfields;
1636 
1637  http->sending = HTTPSEND_BODY;
1638 
1639  conn->fread = (curl_read_callback)readmoredata;
1640  conn->fread_in = (void *)conn;
1641 
1642  /* set the upload size to the progress meter */
1643  Curl_pgrsSetUploadSize(data, http->postsize);
1644 
1645  if(!authdone && !checkheaders(data, "Expect:")) {
1646  /* if not disabled explicitly we add a Expect: 100-continue to the
1647  headers which actually speeds up post operations (as there is
1648  one packet coming back from the web server) */
1649  add_bufferf(req_buffer,
1650  "Expect: 100-continue\r\n");
1651  data->set.expect100header = TRUE;
1652  }
1653 
1654  add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
1655  }
1656  }
1657  else {
1658  add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
1659 
1660  /* set the upload size to the progress meter */
1661  Curl_pgrsSetUploadSize(data, data->set.infilesize);
1662 
1663  /* set the pointer to mark that we will send the post body using
1664  the read callback */
1665  http->postdata = (char *)&http->postdata;
1666  }
1667  /* issue the request */
1668  result = add_buffer_send(req_buffer, conn,
1669  &data->info.request_size);
1670 
1671  if(result)
1672  failf(data, "Failed sending HTTP POST request");
1673  else
1674  result =
1675  Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
1676  &http->readbytecount,
1677  http->postdata?FIRSTSOCKET:-1,
1678  http->postdata?&http->writebytecount:NULL);
1679  break;
1680 
1681  default:
1682  add_buffer(req_buffer, "\r\n", 2);
1683 
1684  /* issue the request */
1685  result = add_buffer_send(req_buffer, conn,
1686  &data->info.request_size);
1687 
1688  if(result)
1689  failf(data, "Failed sending HTTP request");
1690  else
1691  /* HTTP GET/HEAD download: */
1692  result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
1693  &http->readbytecount,
1694  http->postdata?FIRSTSOCKET:-1,
1695  http->postdata?&http->writebytecount:NULL);
1696  }
1697  if(result)
1698  return result;
1699  }
1700 
1701  return CURLE_OK;
1702 }
1703 #endif
bool no_body
Definition: urldata.h:864
#define CLIENTWRITE_BODY
Definition: sendf.h:34
struct CookieInfo * cookies
Definition: urldata.h:901
bool httpproxy
Definition: urldata.h:281
void Curl_formclean(struct FormData *form)
Definition: formdata.c:1060
struct ConnectBits bits
Definition: urldata.h:462
CURLntlm Curl_input_ntlm(struct connectdata *conn, bool proxy, char *header)
curl_off_t bytecount
Definition: urldata.h:437
char buffer[BUFSIZE+1]
Definition: urldata.h:679
void * send_buffer
Definition: urldata.h:234
#define CURLAUTH_BASIC
Definition: curl.h:296
union connectdata::@11 proto
bool http_disable_hostname_check_before_authentication
Definition: urldata.h:858
int curl_socket_t
Definition: setup.h:254
bool forbidchunk
Definition: urldata.h:296
#define FIRSTSOCKET
Definition: urldata.h:394
void * in
Definition: urldata.h:765
long tv_sec
Definition: timeval.h:37
struct DynamicStatic change
Definition: urldata.h:899
#define curlassert(x)
Definition: setup.h:149
CURLcode Curl_http_done(struct connectdata *conn)
Definition: http.c:1000
#define failf
Definition: sendf.h:32
curl_off_t postsize
Definition: urldata.h:224
#define strnequal(a, b, c)
Definition: strequal.h:33
int Curl_FormInit(struct Form *form, struct FormData *formdata)
Definition: formdata.c:1281
char * data
Definition: curl.h:1062
char * useragent
Definition: urldata.h:780
char * customrequest
Definition: urldata.h:821
CURLcode Curl_client_write(struct SessionHandle *data, int type, char *ptr, size_t len)
Definition: sendf.c:319
#define SELECT_ERROR
char * cookie
Definition: urldata.h:801
#define CURL_MAX_WRITE_SIZE
Definition: curl.h:167
size_t Curl_base64_encode(const char *inp, size_t insize, char **outptr)
Definition: base64.c:123
CURLcode
Definition: curl.h:209
#define CURLAUTH_GSSNEGOTIATE
Definition: curl.h:298
curl_off_t readbytecount
Definition: urldata.h:213
CURLdigest
Definition: http_digest.h:26
CURLntlm
Definition: http_ntlm.h:26
bool upload
Definition: urldata.h:866
unsigned short remote_port
Definition: urldata.h:434
GLdouble s
Definition: glext.h:2935
GLenum GLsizei len
Definition: glext.h:3472
struct UrlState state
Definition: urldata.h:903
struct digestdata digest
Definition: urldata.h:706
size_t Curl_FormReader(char *buffer, size_t size, size_t nitems, FILE *mydata)
Definition: formdata.c:1293
char * proxyuser
Definition: urldata.h:449
long request_size
Definition: urldata.h:595
off_t curl_off_t
Definition: curl.h:96
int Curl_read(struct connectdata *conn, curl_socket_t sockfd, char *buf, size_t buffersize, ssize_t *n)
Definition: sendf.c:362
long proxyauth
Definition: urldata.h:772
int i
Definition: process.py:33
Boolean result
#define ssize_t
Definition: config-win32.h:27
enum HTTP::@9 sending
void Curl_http_auth_stage(struct SessionHandle *data, int stage)
Definition: http.c:1043
struct FormData * sendit
Definition: urldata.h:207
CURLcode Curl_write(struct connectdata *conn, curl_socket_t sockfd, void *mem, size_t len, ssize_t *written)
Definition: sendf.c:221
bool tunnel_thru_httpproxy
Definition: urldata.h:849
char * buffer
Definition: http.c:495
curl_off_t resume_from
Definition: urldata.h:442
long timeout
Definition: urldata.h:794
char * nonce
Definition: urldata.h:172
curl_read_callback fread
Definition: urldata.h:221
char * auth_host
Definition: urldata.h:685
struct HTTP * http
Definition: urldata.h:539
#define SELECT_TIMEOUT
char * passwd
Definition: urldata.h:447
long tv_usec
Definition: timeval.h:38
#define PROT_HTTP
Definition: urldata.h:410
GLuint GLuint GLsizei count
Definition: glext.h:2845
CURLcode Curl_http_auth(struct connectdata *conn, int httpcode, char *header)
Definition: http.c:319
char uploadbuffer[BUFSIZE+1]
Definition: urldata.h:680
bool ipv6_ip
Definition: urldata.h:284
struct PureInfo info
Definition: urldata.h:905
bool expect100header
Definition: urldata.h:875
long proxyauthavail
Definition: urldata.h:597
struct curl_slist * headers
Definition: urldata.h:802
#define CURLAUTH_NONE
Definition: curl.h:295
char * hostname
Definition: urldata.h:432
GLuint GLuint end
Definition: glext.h:2845
#define FORMAT_OFF_T
Definition: setup.h:99
char * url
Definition: urldata.h:734
#define NULL
Definition: Lib.h:88
curl_off_t postfieldsize
Definition: urldata.h:783
void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size)
Definition: progress.c:189
#define select(args...)
Definition: amigaos.h:39
struct curl_slist * next
Definition: curl.h:1063
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:2853
GLuint buffer
Definition: glext.h:3108
struct timeval now
Definition: urldata.h:452
char * ppath
Definition: urldata.h:436
char * referer
Definition: urldata.h:742
long httpversion
Definition: urldata.h:822
long authavail
Definition: urldata.h:718
const char * path
Definition: sws.c:117
CURLcode Curl_http_connect(struct connectdata *conn)
Definition: http.c:956
long authwant
Definition: urldata.h:715
char * postdata
Definition: urldata.h:223
CURLcode Curl_http(struct connectdata *conn)
Definition: http.c:1057
CURLdigest Curl_input_digest(struct connectdata *conn, char *header)
Definition: http_digest.c:54
#define CLIENTWRITE_HEADER
Definition: sendf.h:35
struct tm * gmtime(const time_t *)
bool this_is_a_follow
Definition: urldata.h:683
CURLcode Curl_Transfer(struct connectdata *c_conn, int sockindex, curl_off_t size, bool getheader, curl_off_t *bytecountp, int writesockindex, curl_off_t *writecountp)
Definition: transfer.c:1998
void Curl_http_auth_act(struct connectdata *conn)
Definition: http.c:167
#define CURLAUTH_NTLM
Definition: curl.h:299
char * range
Definition: urldata.h:440
long Curl_tvdiff(struct timeval newer, struct timeval older)
Definition: timeval.c:92
long authstage
Definition: urldata.h:712
Definition: curl.h:210
struct SessionHandle * data
Definition: urldata.h:403
curl_read_callback fread
Definition: urldata.h:565
#define checkprefix(a, b)
Definition: strequal.h:37
char * newurl
Definition: urldata.h:517
bool close
Definition: urldata.h:278
size_t Curl_FormReadOneLine(char *buffer, size_t size, size_t nitems, FILE *mydata)
Definition: formdata.c:1339
const char * p_accept
Definition: urldata.h:212
char * strdup(char *s1)
Definition: main.c:183
CURLcode Curl_output_digest(struct connectdata *conn, unsigned char *request, unsigned char *uripath)
Definition: http_digest.c:129
bool proxy_user_passwd
Definition: urldata.h:283
int httpproxycode
Definition: urldata.h:588
char * name
Definition: urldata.h:430
curl_off_t infilesize
Definition: urldata.h:797
int Curl_debug(struct SessionHandle *data, curl_infotype type, char *ptr, size_t size)
Definition: sendf.c:439
#define PORT_HTTPS
Definition: urldata.h:35
curl_read_callback fread
Definition: urldata.h:790
char * proxypasswd
Definition: urldata.h:450
CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy, bool *ready)
CURLcode Curl_getFormData(struct FormData **finalform, struct curl_httppost *post, curl_off_t *sizep)
Definition: formdata.c:1101
curl_socket_t sock[2]
Definition: urldata.h:454
GLuint in
Definition: glext.h:5388
long httpauthavail
Definition: urldata.h:598
char * postfields
Definition: urldata.h:782
bool verbose
Definition: urldata.h:871
GLsizeiptr size
Definition: glext.h:3112
time_t timevalue
Definition: urldata.h:818
#define PROT_HTTPS
Definition: urldata.h:411
void * fread_in
Definition: urldata.h:222
char * encoding
Definition: urldata.h:781
size_t size_max
Definition: http.c:496
curl_off_t postsize
Definition: urldata.h:208
#define infof
Definition: sendf.h:31
void Curl_safefree(void *ptr)
Definition: url.c:172
void * fread_in
Definition: urldata.h:566
#define FALSE
Definition: mprintf.c:70
struct timeval Curl_tvnow(void)
Definition: timeval.c:81
#define SELECT_OK
curl_off_t writebytecount
Definition: urldata.h:214
CURLSHcode Curl_share_lock(struct SessionHandle *data, curl_lock_data type, curl_lock_access accesstype)
Definition: share.c:180
bool upload_chunky
Definition: urldata.h:292
bool Curl_compareheader(char *headerline, const char *header, const char *content)
Definition: http.c:677
struct UserDefined set
Definition: urldata.h:898
struct Form form
Definition: urldata.h:217
bool use_range
Definition: urldata.h:286
long headerbytecount
Definition: urldata.h:438
#define CURLAUTH_DIGEST
Definition: curl.h:297
GLuint res
Definition: glext.h:5385
#define TRUE
Definition: mprintf.c:69
char * postdata
Definition: urldata.h:209
long protocol
Definition: urldata.h:407
#define PORT_HTTP
Definition: urldata.h:34
CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, const char *fmt,...)
Definition: sendf.c:172
Definition: urldata.h:206
CURLcode Curl_SSLConnect(struct connectdata *conn, int sockindex)
Definition: ssluse.c:913
bool retry
Definition: urldata.h:302
struct connectdata::dynamically_allocated_data allocptr
size_t size_used
Definition: http.c:497
#define PROT_FTP
Definition: urldata.h:412
size_t(* curl_read_callback)(char *buffer, size_t size, size_t nitems, void *instream)
Definition: curl.h:174
int() curl_strequal(const char *s1, const char *s2)
Definition: strequal.c:37
Curl_HttpReq httpreq
Definition: urldata.h:820
struct curl_httppost * httppost
Definition: urldata.h:803
curl_TimeCond timecondition
Definition: urldata.h:817
CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, int sockindex, char *hostname, int remote_port)
Definition: http.c:731
CURLSHcode Curl_share_unlock(struct SessionHandle *data, curl_lock_data type)
Definition: share.c:198
struct HTTP::back backup
long httpauth
Definition: urldata.h:771
const char * p_pragma
Definition: urldata.h:211
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
bool user_passwd
Definition: urldata.h:282
#define BUFSIZE
Definition: urldata.h:104
GLuint start
Definition: glext.h:2845
char * user
Definition: urldata.h:446