http.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. /*****************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 2000, Daniel Stenberg, <[email protected]>, et al.
  9. *
  10. * In order to be useful for every potential user, curl and libcurl are
  11. * dual-licensed under the MPL and the MIT/X-derivate licenses.
  12. *
  13. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  14. * copies of the Software, and permit persons to whom the Software is
  15. * furnished to do so, under the terms of the MPL or the MIT/X-derivate
  16. * licenses. You may pick one of these licenses.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * $Id$
  22. *****************************************************************************/
  23. #include "setup.h"
  24. /* -- WIN32 approved -- */
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <stdarg.h>
  28. #include <stdlib.h>
  29. #include <ctype.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <errno.h>
  33. #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
  34. #include <winsock.h>
  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. #include <sys/time.h>
  45. #ifdef HAVE_TIME_H
  46. #ifdef TIME_WITH_SYS_TIME
  47. #include <time.h>
  48. #endif
  49. #endif
  50. #include <sys/resource.h>
  51. #ifdef HAVE_UNISTD_H
  52. #include <unistd.h>
  53. #endif
  54. #include <netdb.h>
  55. #ifdef HAVE_ARPA_INET_H
  56. #include <arpa/inet.h>
  57. #endif
  58. #ifdef HAVE_NET_IF_H
  59. #include <net/if.h>
  60. #endif
  61. #include <sys/ioctl.h>
  62. #include <signal.h>
  63. #ifdef HAVE_SYS_PARAM_H
  64. #include <sys/param.h>
  65. #endif
  66. #ifdef HAVE_SYS_SELECT_H
  67. #include <sys/select.h>
  68. #endif
  69. #endif
  70. #include "urldata.h"
  71. #include <curl/curl.h>
  72. #include "transfer.h"
  73. #include "sendf.h"
  74. #include "formdata.h"
  75. #include "progress.h"
  76. #include "base64.h"
  77. #include "cookie.h"
  78. #include "strequal.h"
  79. #include "ssluse.h"
  80. #define _MPRINTF_REPLACE /* use our functions only */
  81. #include <curl/mprintf.h>
  82. /* The last #include file should be: */
  83. #ifdef MALLOCDEBUG
  84. #include "memdebug.h"
  85. #endif
  86. /* ------------------------------------------------------------------------- */
  87. /*
  88. * The add_buffer series of functions are used to build one large memory chunk
  89. * from repeated function invokes. Used so that the entire HTTP request can
  90. * be sent in one go.
  91. */
  92. static CURLcode
  93. add_buffer(send_buffer *in, const void *inptr, size_t size);
  94. /*
  95. * add_buffer_init() returns a fine buffer struct
  96. */
  97. static
  98. send_buffer *add_buffer_init(void)
  99. {
  100. send_buffer *blonk;
  101. blonk=(send_buffer *)malloc(sizeof(send_buffer));
  102. if(blonk) {
  103. memset(blonk, 0, sizeof(send_buffer));
  104. return blonk;
  105. }
  106. return NULL; /* failed, go home */
  107. }
  108. /*
  109. * add_buffer_send() sends a buffer and frees all associated memory.
  110. */
  111. static
  112. CURLcode add_buffer_send(int sockfd, struct connectdata *conn, send_buffer *in,
  113. long *bytes_written)
  114. {
  115. ssize_t amount;
  116. CURLcode res;
  117. char *ptr;
  118. int size;
  119. if(conn->data->set.verbose) {
  120. fputs("> ", conn->data->set.err);
  121. /* this data _may_ contain binary stuff */
  122. fwrite(in->buffer, in->size_used, 1, conn->data->set.err);
  123. }
  124. /* The looping below is required since we use non-blocking sockets, but due
  125. to the circumstances we will just loop and try again and again etc */
  126. ptr = in->buffer;
  127. size = in->size_used;
  128. do {
  129. res = Curl_write(conn, sockfd, ptr, size, &amount);
  130. if(CURLE_OK != res)
  131. break;
  132. if(amount != size) {
  133. size -= amount;
  134. ptr += amount;
  135. }
  136. else
  137. break;
  138. } while(1);
  139. if(in->buffer)
  140. free(in->buffer);
  141. free(in);
  142. *bytes_written = amount;
  143. return res;
  144. }
  145. /*
  146. * add_bufferf() builds a buffer from the formatted input
  147. */
  148. static
  149. CURLcode add_bufferf(send_buffer *in, const char *fmt, ...)
  150. {
  151. CURLcode result = CURLE_OUT_OF_MEMORY;
  152. char *s;
  153. va_list ap;
  154. va_start(ap, fmt);
  155. s = vaprintf(fmt, ap); /* this allocs a new string to append */
  156. va_end(ap);
  157. if(s) {
  158. result = add_buffer(in, s, strlen(s));
  159. free(s);
  160. }
  161. return result;
  162. }
  163. /*
  164. * add_buffer() appends a memory chunk to the existing one
  165. */
  166. static
  167. CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size)
  168. {
  169. char *new_rb;
  170. int new_size;
  171. if(!in->buffer ||
  172. ((in->size_used + size) > (in->size_max - 1))) {
  173. new_size = (in->size_used+size)*2;
  174. if(in->buffer)
  175. /* we have a buffer, enlarge the existing one */
  176. new_rb = (char *)realloc(in->buffer, new_size);
  177. else
  178. /* create a new buffer */
  179. new_rb = (char *)malloc(new_size);
  180. if(!new_rb)
  181. return CURLE_OUT_OF_MEMORY;
  182. in->buffer = new_rb;
  183. in->size_max = new_size;
  184. }
  185. memcpy(&in->buffer[in->size_used], inptr, size);
  186. in->size_used += size;
  187. return CURLE_OK;
  188. }
  189. /* end of the add_buffer functions */
  190. /* ------------------------------------------------------------------------- */
  191. /*
  192. * This function checks the linked list of custom HTTP headers for a particular
  193. * header (prefix).
  194. */
  195. static bool checkheaders(struct SessionHandle *data, const char *thisheader)
  196. {
  197. struct curl_slist *head;
  198. size_t thislen = strlen(thisheader);
  199. for(head = data->set.headers; head; head=head->next) {
  200. if(strnequal(head->data, thisheader, thislen)) {
  201. return TRUE;
  202. }
  203. }
  204. return FALSE;
  205. }
  206. /*
  207. * ConnectHTTPProxyTunnel() requires that we're connected to a HTTP proxy. This
  208. * function will issue the necessary commands to get a seamless tunnel through
  209. * this proxy. After that, the socket can be used just as a normal socket.
  210. */
  211. CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
  212. int tunnelsocket,
  213. char *hostname, int remote_port)
  214. {
  215. int httperror=0;
  216. int subversion=0;
  217. struct SessionHandle *data=conn->data;
  218. CURLcode result;
  219. int res;
  220. int nread; /* total size read */
  221. int perline; /* count bytes per line */
  222. bool keepon=TRUE;
  223. ssize_t gotbytes;
  224. char *ptr;
  225. int timeout = 3600; /* default timeout in seconds */
  226. struct timeval interval;
  227. fd_set rkeepfd;
  228. fd_set readfd;
  229. char *line_start;
  230. #define SELECT_OK 0
  231. #define SELECT_ERROR 1
  232. #define SELECT_TIMEOUT 2
  233. int error = SELECT_OK;
  234. infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
  235. /* OK, now send the connect request to the proxy */
  236. result =
  237. Curl_sendf(tunnelsocket, conn,
  238. "CONNECT %s:%d HTTP/1.0\015\012"
  239. "%s"
  240. "%s"
  241. "\r\n",
  242. hostname, remote_port,
  243. (conn->bits.proxy_user_passwd)?conn->allocptr.proxyuserpwd:"",
  244. (data->set.useragent?conn->allocptr.uagent:"")
  245. );
  246. if(result) {
  247. failf(data, "Failed sending CONNECT to proxy");
  248. return result;
  249. }
  250. /* Now, read the full reply we get from the proxy */
  251. if(data->set.timeout) {
  252. /* if timeout is requested, find out how much remaining time we have */
  253. timeout = data->set.timeout - /* timeout time */
  254. Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
  255. if(timeout <=0 ) {
  256. failf(data, "Transfer aborted due to timeout");
  257. return -SELECT_TIMEOUT; /* already too little time */
  258. }
  259. }
  260. FD_ZERO (&readfd); /* clear it */
  261. FD_SET (tunnelsocket, &readfd); /* read socket */
  262. /* get this in a backup variable to be able to restore it on each lap in the
  263. select() loop */
  264. rkeepfd = readfd;
  265. ptr=data->state.buffer;
  266. line_start = ptr;
  267. nread=0;
  268. perline=0;
  269. keepon=TRUE;
  270. while((nread<BUFSIZE) && (keepon && !error)) {
  271. readfd = rkeepfd; /* set every lap */
  272. interval.tv_sec = timeout;
  273. interval.tv_usec = 0;
  274. switch (select (tunnelsocket+1, &readfd, NULL, NULL, &interval)) {
  275. case -1: /* select() error, stop reading */
  276. error = SELECT_ERROR;
  277. failf(data, "Transfer aborted due to select() error");
  278. break;
  279. case 0: /* timeout */
  280. error = SELECT_TIMEOUT;
  281. failf(data, "Transfer aborted due to timeout");
  282. break;
  283. default:
  284. /*
  285. * This code previously didn't use the kerberos sec_read() code
  286. * to read, but when we use Curl_read() it may do so. Do confirm
  287. * that this is still ok and then remove this comment!
  288. */
  289. res= Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread,
  290. &gotbytes);
  291. if(res< 0)
  292. /* EWOULDBLOCK */
  293. continue; /* go loop yourself */
  294. else if(res)
  295. keepon = FALSE;
  296. else if(gotbytes <= 0) {
  297. keepon = FALSE;
  298. error = SELECT_ERROR;
  299. failf(data, "Connection aborted");
  300. }
  301. else {
  302. /* we got a whole chunk of data, which can be anything from one
  303. * byte to a set of lines and possibly just a piece of the last
  304. * line */
  305. int i;
  306. nread += gotbytes;
  307. for(i = 0; i < gotbytes; ptr++, i++) {
  308. perline++; /* amount of bytes in this line so far */
  309. if(*ptr=='\n') {
  310. /* a newline is CRLF in ftp-talk, so the CR is ignored as
  311. the line isn't really terminated until the LF comes */
  312. /* output debug output if that is requested */
  313. if(data->set.verbose) {
  314. fputs("< ", data->set.err);
  315. fwrite(line_start, perline, 1, data->set.err);
  316. /* no need to output LF here, it is part of the data */
  317. }
  318. if('\r' == line_start[0]) {
  319. /* end of headers */
  320. keepon=FALSE;
  321. break; /* breaks out of loop, not switch */
  322. }
  323. if(2 == sscanf(line_start, "HTTP/1.%d %d",
  324. &subversion,
  325. &httperror)) {
  326. ;
  327. }
  328. perline=0; /* line starts over here */
  329. line_start = ptr+1;
  330. }
  331. }
  332. }
  333. break;
  334. } /* switch */
  335. } /* while there's buffer left and loop is requested */
  336. if(error)
  337. return CURLE_READ_ERROR;
  338. if(200 != httperror) {
  339. if(407 == httperror)
  340. /* Added Nov 6 1998 */
  341. failf(data, "Proxy requires authorization!");
  342. else
  343. failf(data, "Received error code %d from proxy", httperror);
  344. return CURLE_READ_ERROR;
  345. }
  346. infof (data, "Proxy replied to CONNECT request\n");
  347. return CURLE_OK;
  348. }
  349. /*
  350. * HTTP stuff to do at connect-time.
  351. */
  352. CURLcode Curl_http_connect(struct connectdata *conn)
  353. {
  354. struct SessionHandle *data;
  355. CURLcode result;
  356. data=conn->data;
  357. /* If we are not using a proxy and we want a secure connection,
  358. * perform SSL initialization & connection now.
  359. * If using a proxy with https, then we must tell the proxy to CONNECT
  360. * us to the host we want to talk to. Only after the connect
  361. * has occured, can we start talking SSL
  362. */
  363. if(data->change.proxy &&
  364. ((conn->protocol & PROT_HTTPS) || data->set.tunnel_thru_httpproxy)) {
  365. /* either HTTPS over proxy, OR explicitly asked for a tunnel */
  366. result = Curl_ConnectHTTPProxyTunnel(conn, conn->firstsocket,
  367. conn->hostname, conn->remote_port);
  368. if(CURLE_OK != result)
  369. return result;
  370. }
  371. if(conn->protocol & PROT_HTTPS) {
  372. /* now, perform the SSL initialization for this socket */
  373. result = Curl_SSLConnect(conn);
  374. if(result)
  375. return result;
  376. }
  377. if(conn->bits.user_passwd && !data->state.this_is_a_follow) {
  378. /* Authorization: is requested, this is not a followed location, get the
  379. original host name */
  380. data->state.auth_host = strdup(conn->hostname);
  381. }
  382. return CURLE_OK;
  383. }
  384. CURLcode Curl_http_done(struct connectdata *conn)
  385. {
  386. struct SessionHandle *data;
  387. long *bytecount = &conn->bytecount;
  388. struct HTTP *http;
  389. data=conn->data;
  390. http=conn->proto.http;
  391. if(HTTPREQ_POST_FORM == data->set.httpreq) {
  392. *bytecount = http->readbytecount + http->writebytecount;
  393. Curl_formclean(http->sendit); /* Now free that whole lot */
  394. data->set.fread = http->storefread; /* restore */
  395. data->set.in = http->in; /* restore */
  396. }
  397. else if(HTTPREQ_PUT == data->set.httpreq) {
  398. *bytecount = http->readbytecount + http->writebytecount;
  399. }
  400. if(0 == (http->readbytecount + conn->headerbytecount)) {
  401. /* nothing was read from the HTTP server, this can't be right
  402. so we return an error here */
  403. failf(data, "Empty reply from server");
  404. return CURLE_GOT_NOTHING;
  405. }
  406. return CURLE_OK;
  407. }
  408. CURLcode Curl_http(struct connectdata *conn)
  409. {
  410. struct SessionHandle *data=conn->data;
  411. char *buf = data->state.buffer; /* this is a short cut to the buffer */
  412. CURLcode result=CURLE_OK;
  413. struct HTTP *http;
  414. struct Cookie *co=NULL; /* no cookies from start */
  415. char *ppath = conn->ppath; /* three previous function arguments */
  416. char *host = conn->name;
  417. long *bytecount = &conn->bytecount;
  418. if(!conn->proto.http) {
  419. /* Only allocate this struct if we don't already have it! */
  420. http = (struct HTTP *)malloc(sizeof(struct HTTP));
  421. if(!http)
  422. return CURLE_OUT_OF_MEMORY;
  423. memset(http, 0, sizeof(struct HTTP));
  424. conn->proto.http = http;
  425. }
  426. else
  427. http = conn->proto.http;
  428. /* We default to persistant connections */
  429. conn->bits.close = FALSE;
  430. if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) &&
  431. data->set.upload) {
  432. data->set.httpreq = HTTPREQ_PUT;
  433. }
  434. /* The User-Agent string has been built in url.c already, because it might
  435. have been used in the proxy connect, but if we have got a header with
  436. the user-agent string specified, we erase the previously made string
  437. here. */
  438. if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
  439. free(conn->allocptr.uagent);
  440. conn->allocptr.uagent=NULL;
  441. }
  442. if((conn->bits.user_passwd) && !checkheaders(data, "Authorization:")) {
  443. char *authorization;
  444. /* To prevent the user+password to get sent to other than the original
  445. host due to a location-follow, we do some weirdo checks here */
  446. if(!data->state.this_is_a_follow ||
  447. !data->state.auth_host ||
  448. strequal(data->state.auth_host, conn->hostname)) {
  449. sprintf(data->state.buffer, "%s:%s",
  450. data->state.user, data->state.passwd);
  451. if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer),
  452. &authorization) >= 0) {
  453. if(conn->allocptr.userpwd)
  454. free(conn->allocptr.userpwd);
  455. conn->allocptr.userpwd = aprintf( "Authorization: Basic %s\015\012",
  456. authorization);
  457. free(authorization);
  458. }
  459. }
  460. }
  461. if((data->change.referer) && !checkheaders(data, "Referer:")) {
  462. if(conn->allocptr.ref)
  463. free(conn->allocptr.ref);
  464. conn->allocptr.ref = aprintf("Referer: %s\015\012", data->change.referer);
  465. }
  466. if(data->set.cookie && !checkheaders(data, "Cookie:")) {
  467. if(conn->allocptr.cookie)
  468. free(conn->allocptr.cookie);
  469. conn->allocptr.cookie = aprintf("Cookie: %s\015\012", data->set.cookie);
  470. }
  471. if(data->cookies) {
  472. co = Curl_cookie_getlist(data->cookies,
  473. host, ppath,
  474. conn->protocol&PROT_HTTPS?TRUE:FALSE);
  475. }
  476. if (data->change.proxy &&
  477. !data->set.tunnel_thru_httpproxy &&
  478. !(conn->protocol&PROT_HTTPS)) {
  479. /* The path sent to the proxy is in fact the entire URL */
  480. ppath = data->change.url;
  481. }
  482. if(HTTPREQ_POST_FORM == data->set.httpreq) {
  483. /* we must build the whole darned post sequence first, so that we have
  484. a size of the whole shebang before we start to send it */
  485. http->sendit = Curl_getFormData(data->set.httppost, &http->postsize);
  486. }
  487. if(!checkheaders(data, "Host:")) {
  488. /* if ptr_host is already set, it is almost OK since we only re-use
  489. connections to the very same host and port, but when we use a HTTP
  490. proxy we have a persistant connect and yet we must change the Host:
  491. header! */
  492. if(conn->allocptr.host)
  493. free(conn->allocptr.host);
  494. if(((conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTPS)) ||
  495. (!(conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTP)) )
  496. /* If (HTTPS on port 443) OR (non-HTTPS on port 80) then don't include
  497. the port number in the host string */
  498. conn->allocptr.host = aprintf("Host: %s\r\n", host);
  499. else
  500. conn->allocptr.host = aprintf("Host: %s:%d\r\n", host,
  501. conn->remote_port);
  502. }
  503. if(!checkheaders(data, "Pragma:"))
  504. http->p_pragma = "Pragma: no-cache\r\n";
  505. if(!checkheaders(data, "Accept:"))
  506. http->p_accept = "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n";
  507. if(( (HTTPREQ_POST == data->set.httpreq) ||
  508. (HTTPREQ_POST_FORM == data->set.httpreq) ||
  509. (HTTPREQ_PUT == data->set.httpreq) ) &&
  510. conn->resume_from) {
  511. /**********************************************************************
  512. * Resuming upload in HTTP means that we PUT or POST and that we have
  513. * got a resume_from value set. The resume value has already created
  514. * a Range: header that will be passed along. We need to "fast forward"
  515. * the file the given number of bytes and decrease the assume upload
  516. * file size before we continue this venture in the dark lands of HTTP.
  517. *********************************************************************/
  518. if(conn->resume_from < 0 ) {
  519. /*
  520. * This is meant to get the size of the present remote-file by itself.
  521. * We don't support this now. Bail out!
  522. */
  523. conn->resume_from = 0;
  524. }
  525. if(conn->resume_from) {
  526. /* do we still game? */
  527. int passed=0;
  528. /* Now, let's read off the proper amount of bytes from the
  529. input. If we knew it was a proper file we could've just
  530. fseek()ed but we only have a stream here */
  531. do {
  532. int readthisamountnow = (conn->resume_from - passed);
  533. int actuallyread;
  534. if(readthisamountnow > BUFSIZE)
  535. readthisamountnow = BUFSIZE;
  536. actuallyread =
  537. data->set.fread(data->state.buffer, 1, readthisamountnow,
  538. data->set.in);
  539. passed += actuallyread;
  540. if(actuallyread != readthisamountnow) {
  541. failf(data, "Could only read %d bytes from the input",
  542. passed);
  543. return CURLE_READ_ERROR;
  544. }
  545. } while(passed != conn->resume_from); /* loop until done */
  546. /* now, decrease the size of the read */
  547. if(data->set.infilesize>0) {
  548. data->set.infilesize -= conn->resume_from;
  549. if(data->set.infilesize <= 0) {
  550. failf(data, "File already completely uploaded");
  551. return CURLE_PARTIAL_FILE;
  552. }
  553. }
  554. /* we've passed, proceed as normal */
  555. }
  556. }
  557. if(conn->bits.use_range) {
  558. /*
  559. * A range is selected. We use different headers whether we're downloading
  560. * or uploading and we always let customized headers override our internal
  561. * ones if any such are specified.
  562. */
  563. if((data->set.httpreq == HTTPREQ_GET) &&
  564. !checkheaders(data, "Range:")) {
  565. conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", conn->range);
  566. }
  567. else if((data->set.httpreq != HTTPREQ_GET) &&
  568. !checkheaders(data, "Content-Range:")) {
  569. if(conn->resume_from) {
  570. /* This is because "resume" was selected */
  571. long total_expected_size= conn->resume_from + data->set.infilesize;
  572. conn->allocptr.rangeline = aprintf("Content-Range: bytes %s%ld/%ld\r\n",
  573. conn->range, total_expected_size-1,
  574. total_expected_size);
  575. }
  576. else {
  577. /* Range was selected and then we just pass the incoming range and
  578. append total size */
  579. conn->allocptr.rangeline = aprintf("Content-Range: bytes %s/%d\r\n",
  580. conn->range, data->set.infilesize);
  581. }
  582. }
  583. }
  584. do {
  585. /* Use 1.1 unless the use specificly asked for 1.0 */
  586. const char *httpstring=
  587. data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1";
  588. send_buffer *req_buffer;
  589. struct curl_slist *headers=data->set.headers;
  590. /* initialize a dynamic send-buffer */
  591. req_buffer = add_buffer_init();
  592. /* add the main request stuff */
  593. add_bufferf(req_buffer,
  594. "%s " /* GET/HEAD/POST/PUT */
  595. "%s HTTP/%s\r\n" /* path */
  596. "%s" /* proxyuserpwd */
  597. "%s" /* userpwd */
  598. "%s" /* range */
  599. "%s" /* user agent */
  600. "%s" /* cookie */
  601. "%s" /* host */
  602. "%s" /* pragma */
  603. "%s" /* accept */
  604. "%s", /* referer */
  605. data->set.customrequest?data->set.customrequest:
  606. (data->set.no_body?"HEAD":
  607. ((HTTPREQ_POST == data->set.httpreq) ||
  608. (HTTPREQ_POST_FORM == data->set.httpreq))?"POST":
  609. (HTTPREQ_PUT == data->set.httpreq)?"PUT":"GET"),
  610. ppath, httpstring,
  611. (conn->bits.proxy_user_passwd &&
  612. conn->allocptr.proxyuserpwd)?conn->allocptr.proxyuserpwd:"",
  613. (conn->bits.user_passwd && conn->allocptr.userpwd)?
  614. conn->allocptr.userpwd:"",
  615. (conn->bits.use_range && conn->allocptr.rangeline)?
  616. conn->allocptr.rangeline:"",
  617. (data->set.useragent && *data->set.useragent && conn->allocptr.uagent)?
  618. conn->allocptr.uagent:"",
  619. (conn->allocptr.cookie?conn->allocptr.cookie:""), /* Cookie: <data> */
  620. (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */
  621. http->p_pragma?http->p_pragma:"",
  622. http->p_accept?http->p_accept:"",
  623. (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: <data> <CRLF> */
  624. );
  625. if(co) {
  626. int count=0;
  627. struct Cookie *store=co;
  628. /* now loop through all cookies that matched */
  629. while(co) {
  630. if(co->value && strlen(co->value)) {
  631. if(0 == count) {
  632. add_bufferf(req_buffer, "Cookie: ");
  633. }
  634. add_bufferf(req_buffer,
  635. "%s%s=%s", count?"; ":"", co->name, co->value);
  636. count++;
  637. }
  638. co = co->next; /* next cookie please */
  639. }
  640. if(count) {
  641. add_buffer(req_buffer, "\r\n", 2);
  642. }
  643. Curl_cookie_freelist(store); /* free the cookie list */
  644. co=NULL;
  645. }
  646. if(data->set.timecondition) {
  647. struct tm *thistime;
  648. /* Phil Karn (Fri, 13 Apr 2001) pointed out that the If-Modified-Since
  649. * header family should have their times set in GMT as RFC2616 defines:
  650. * "All HTTP date/time stamps MUST be represented in Greenwich Mean Time
  651. * (GMT), without exception. For the purposes of HTTP, GMT is exactly
  652. * equal to UTC (Coordinated Universal Time)." (see page 20 of RFC2616).
  653. */
  654. #ifdef HAVE_GMTIME_R
  655. /* thread-safe version */
  656. struct tm keeptime;
  657. thistime = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
  658. #else
  659. thistime = gmtime(&data->set.timevalue);
  660. #endif
  661. if(NULL == thistime) {
  662. failf(data, "localtime() failed!");
  663. return CURLE_OUT_OF_MEMORY;
  664. }
  665. #ifdef HAVE_STRFTIME
  666. /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
  667. strftime(buf, BUFSIZE-1, "%a, %d %b %Y %H:%M:%S GMT", thistime);
  668. #else
  669. /* TODO: Right, we *could* write a replacement here */
  670. strcpy(buf, "no strftime() support");
  671. #endif
  672. switch(data->set.timecondition) {
  673. case TIMECOND_IFMODSINCE:
  674. default:
  675. add_bufferf(req_buffer,
  676. "If-Modified-Since: %s\r\n", buf);
  677. break;
  678. case TIMECOND_IFUNMODSINCE:
  679. add_bufferf(req_buffer,
  680. "If-Unmodified-Since: %s\r\n", buf);
  681. break;
  682. case TIMECOND_LASTMOD:
  683. add_bufferf(req_buffer,
  684. "Last-Modified: %s\r\n", buf);
  685. break;
  686. }
  687. }
  688. while(headers) {
  689. char *ptr = strchr(headers->data, ':');
  690. if(ptr) {
  691. /* we require a colon for this to be a true header */
  692. ptr++; /* pass the colon */
  693. while(*ptr && isspace((int)*ptr))
  694. ptr++;
  695. if(*ptr) {
  696. /* only send this if the contents was non-blank */
  697. add_bufferf(req_buffer, "%s\r\n", headers->data);
  698. }
  699. }
  700. headers = headers->next;
  701. }
  702. if(HTTPREQ_POST_FORM == data->set.httpreq) {
  703. if(Curl_FormInit(&http->form, http->sendit)) {
  704. failf(data, "Internal HTTP POST error!");
  705. return CURLE_HTTP_POST_ERROR;
  706. }
  707. http->storefread = data->set.fread; /* backup */
  708. http->in = data->set.in; /* backup */
  709. data->set.fread = (curl_read_callback)
  710. Curl_FormReader; /* set the read function to read from the
  711. generated form data */
  712. data->set.in = (FILE *)&http->form;
  713. add_bufferf(req_buffer,
  714. "Content-Length: %d\r\n", http->postsize);
  715. if(!checkheaders(data, "Expect:")) {
  716. /* if not disabled explicitly we add a Expect: 100-continue
  717. to the headers which actually speeds up post operations (as
  718. there is one packet coming back from the web server) */
  719. add_bufferf(req_buffer,
  720. "Expect: 100-continue\r\n");
  721. data->set.expect100header = TRUE;
  722. }
  723. if(!checkheaders(data, "Content-Type:")) {
  724. /* Get Content-Type: line from Curl_FormReadOneLine, which happens
  725. to always be the first line. We can know this for sure since
  726. we always build the formpost linked list the same way!
  727. The Content-Type header line also contains the MIME boundary
  728. string etc why disabling this header is likely to not make things
  729. work, but we support it anyway.
  730. */
  731. char contentType[256];
  732. int linelength=0;
  733. linelength = Curl_FormReadOneLine (contentType,
  734. sizeof(contentType),
  735. 1,
  736. (FILE *)&http->form);
  737. if(linelength == -1) {
  738. failf(data, "Could not get Content-Type header line!");
  739. return CURLE_HTTP_POST_ERROR;
  740. }
  741. add_buffer(req_buffer, contentType, linelength);
  742. }
  743. /* make the request end in a true CRLF */
  744. add_buffer(req_buffer, "\r\n", 2);
  745. /* set upload size to the progress meter */
  746. Curl_pgrsSetUploadSize(data, http->postsize);
  747. /* fire away the whole request to the server */
  748. result = add_buffer_send(conn->firstsocket, conn, req_buffer,
  749. &data->info.request_size);
  750. if(result)
  751. failf(data, "Failed sending POST request");
  752. else
  753. /* setup variables for the upcoming transfer */
  754. result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
  755. &http->readbytecount,
  756. conn->firstsocket,
  757. &http->writebytecount);
  758. if(result) {
  759. Curl_formclean(http->sendit); /* free that whole lot */
  760. return result;
  761. }
  762. }
  763. else if(HTTPREQ_PUT == data->set.httpreq) {
  764. /* Let's PUT the data to the server! */
  765. if(data->set.infilesize>0) {
  766. add_bufferf(req_buffer,
  767. "Content-Length: %d\r\n\r\n", /* file size */
  768. data->set.infilesize );
  769. }
  770. else
  771. add_bufferf(req_buffer, "\015\012");
  772. /* set the upload size to the progress meter */
  773. Curl_pgrsSetUploadSize(data, data->set.infilesize);
  774. /* this sends the buffer and frees all the buffer resources */
  775. result = add_buffer_send(conn->firstsocket, conn, req_buffer,
  776. &data->info.request_size);
  777. if(result)
  778. failf(data, "Faied sending POST request");
  779. else
  780. /* prepare for transfer */
  781. result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
  782. &http->readbytecount,
  783. conn->firstsocket,
  784. &http->writebytecount);
  785. if(result)
  786. return result;
  787. }
  788. else {
  789. if(HTTPREQ_POST == data->set.httpreq) {
  790. /* this is the simple POST, using x-www-form-urlencoded style */
  791. if(!data->set.postfields) {
  792. /*
  793. * This is an attempt to do a POST without having anything to
  794. * actually send. Let's make a NULL pointer equal "" here. Good/bad
  795. * ?
  796. */
  797. data->set.postfields = (char *)"";
  798. data->set.postfieldsize = 0; /* it might been set to something illegal,
  799. anything > 0 would be! */
  800. }
  801. if(!checkheaders(data, "Content-Length:"))
  802. /* we allow replacing this header, although it isn't very wise to
  803. actually set your own */
  804. add_bufferf(req_buffer,
  805. "Content-Length: %d\r\n",
  806. (data->set.postfieldsize?data->set.postfieldsize:
  807. strlen(data->set.postfields)) );
  808. if(!checkheaders(data, "Content-Type:"))
  809. add_bufferf(req_buffer,
  810. "Content-Type: application/x-www-form-urlencoded\r\n");
  811. /* and here comes the actual data */
  812. if(data->set.postfieldsize) {
  813. add_buffer(req_buffer, "\r\n", 2);
  814. add_buffer(req_buffer, data->set.postfields,
  815. data->set.postfieldsize);
  816. }
  817. else {
  818. add_bufferf(req_buffer,
  819. "\r\n"
  820. "%s",
  821. data->set.postfields );
  822. }
  823. }
  824. else
  825. add_buffer(req_buffer, "\r\n", 2);
  826. /* issue the request */
  827. result = add_buffer_send(conn->firstsocket, conn, req_buffer,
  828. &data->info.request_size);
  829. if(result)
  830. failf(data, "Failed sending HTTP request");
  831. else
  832. /* HTTP GET/HEAD download: */
  833. result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, bytecount,
  834. -1, NULL); /* nothing to upload */
  835. }
  836. if(result)
  837. return result;
  838. } while (0); /* this is just a left-over from the multiple document download
  839. attempts */
  840. return CURLE_OK;
  841. }
  842. /*
  843. * local variables:
  844. * eval: (load-file "../curl-mode.el")
  845. * end:
  846. * vim600: fdm=marker
  847. * vim: et sw=2 ts=2 sts=2 tw=78
  848. */