http.c 32 KB

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