00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "setup.h"
00025
00026
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include <stdarg.h>
00030 #include <stdlib.h>
00031 #include <ctype.h>
00032 #include <errno.h>
00033
00034 #include "strtoofft.h"
00035 #include "strequal.h"
00036
00037 #ifdef WIN32
00038 #include <time.h>
00039 #include <io.h>
00040 #else
00041 #ifdef HAVE_SYS_SOCKET_H
00042 #include <sys/socket.h>
00043 #endif
00044 #ifdef HAVE_NETINET_IN_H
00045 #include <netinet/in.h>
00046 #endif
00047 #ifdef HAVE_SYS_TIME_H
00048 #include <sys/time.h>
00049 #endif
00050 #ifdef HAVE_UNISTD_H
00051 #include <unistd.h>
00052 #endif
00053 #ifdef HAVE_NETDB_H
00054 #include <netdb.h>
00055 #endif
00056 #ifdef HAVE_ARPA_INET_H
00057 #include <arpa/inet.h>
00058 #endif
00059 #ifdef HAVE_NET_IF_H
00060 #include <net/if.h>
00061 #endif
00062 #ifdef HAVE_SYS_IOCTL_H
00063 #include <sys/ioctl.h>
00064 #endif
00065 #include <signal.h>
00066
00067 #ifdef HAVE_SYS_PARAM_H
00068 #include <sys/param.h>
00069 #endif
00070
00071 #ifdef HAVE_SYS_SELECT_H
00072 #include <sys/select.h>
00073 #endif
00074
00075 #ifndef HAVE_SOCKET
00076 #error "We can't compile without socket() support!"
00077 #endif
00078
00079 #endif
00080
00081 #include "urldata.h"
00082 #include <curl/curl.h>
00083 #include "netrc.h"
00084
00085 #include "content_encoding.h"
00086 #include "hostip.h"
00087 #include "transfer.h"
00088 #include "sendf.h"
00089 #include "speedcheck.h"
00090 #include "progress.h"
00091 #include "http.h"
00092 #include "url.h"
00093 #include "getinfo.h"
00094 #include "sslgen.h"
00095 #include "http_digest.h"
00096 #include "http_ntlm.h"
00097 #include "http_negotiate.h"
00098 #include "share.h"
00099 #include "memory.h"
00100 #include "select.h"
00101 #include "multiif.h"
00102 #include "easyif.h"
00103
00104 #define _MPRINTF_REPLACE
00105 #include <curl/mprintf.h>
00106
00107
00108 #include "memdebug.h"
00109
00110 #define CURL_TIMEOUT_EXPECT_100 1000
00111
00112
00113
00114
00115
00116 CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
00117 {
00118 struct SessionHandle *data = conn->data;
00119 size_t buffersize = (size_t)bytes;
00120 int nread;
00121
00122 if(conn->bits.upload_chunky) {
00123
00124 buffersize -= (8 + 2 + 2);
00125 data->reqdata.upload_fromhere += 10;
00126 }
00127
00128
00129
00130 nread = (int)conn->fread(data->reqdata.upload_fromhere, 1,
00131 buffersize, conn->fread_in);
00132
00133 if(nread == CURL_READFUNC_ABORT) {
00134 failf(data, "operation aborted by callback\n");
00135 return CURLE_ABORTED_BY_CALLBACK;
00136 }
00137
00138 if(!conn->bits.forbidchunk && conn->bits.upload_chunky) {
00139
00140 char hexbuffer[11];
00141 int hexlen = snprintf(hexbuffer, sizeof(hexbuffer),
00142 "%x\r\n", nread);
00143
00144 data->reqdata.upload_fromhere -= hexlen;
00145 nread += hexlen;
00146
00147
00148 memcpy(data->reqdata.upload_fromhere, hexbuffer, hexlen);
00149
00150
00151 memcpy(data->reqdata.upload_fromhere + nread, "\r\n", 2);
00152
00153 if((nread - hexlen) == 0) {
00154
00155 data->reqdata.keep.upload_done = TRUE;
00156 }
00157
00158 nread+=2;
00159 }
00160
00161 *nreadp = nread;
00162
00163 #ifdef CURL_DOES_CONVERSIONS
00164 if(data->set.prefer_ascii) {
00165 CURLcode res;
00166 res = Curl_convert_to_network(data, data->reqdata.upload_fromhere, nread);
00167
00168 if(res != CURLE_OK) {
00169 return(res);
00170 }
00171 }
00172 #endif
00173
00174 return CURLE_OK;
00175 }
00176
00177
00178
00179
00180
00181
00182 static bool
00183 checkhttpprefix(struct SessionHandle *data,
00184 const char *s)
00185 {
00186 struct curl_slist *head = data->set.http200aliases;
00187 bool rc = FALSE;
00188 #ifdef CURL_DOES_CONVERSIONS
00189
00190 char *scratch = calloc(1, strlen(s)+1);
00191 if (NULL == scratch) {
00192 failf (data, "Failed to calloc memory for conversion!");
00193 return FALSE;
00194 }
00195 strcpy(scratch, s);
00196 if (CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
00197
00198 free(scratch);
00199 return FALSE;
00200 }
00201 s = scratch;
00202 #endif
00203
00204 while (head) {
00205 if (checkprefix(head->data, s)) {
00206 rc = TRUE;
00207 break;
00208 }
00209 head = head->next;
00210 }
00211
00212 if ((rc != TRUE) && (checkprefix("HTTP/", s))) {
00213 rc = TRUE;
00214 }
00215
00216 #ifdef CURL_DOES_CONVERSIONS
00217 free(scratch);
00218 #endif
00219 return rc;
00220 }
00221
00222
00223
00224
00225
00226
00227 CURLcode Curl_readrewind(struct connectdata *conn)
00228 {
00229 struct SessionHandle *data = conn->data;
00230
00231 conn->bits.rewindaftersend = FALSE;
00232
00233
00234
00235
00236 if(data->set.postfields ||
00237 (data->set.httpreq == HTTPREQ_POST_FORM))
00238 ;
00239 else {
00240 if(data->set.ioctl) {
00241 curlioerr err;
00242
00243 err = (data->set.ioctl) (data, CURLIOCMD_RESTARTREAD,
00244 data->set.ioctl_client);
00245 infof(data, "the ioctl callback returned %d\n", (int)err);
00246
00247 if(err) {
00248
00249 failf(data, "ioctl callback returned error %d\n", (int)err);
00250 return CURLE_SEND_FAIL_REWIND;
00251 }
00252 }
00253 else {
00254
00255
00256
00257 if(data->set.fread == (curl_read_callback)fread) {
00258 if(-1 != fseek(data->set.in, 0, SEEK_SET))
00259
00260 return CURLE_OK;
00261 }
00262
00263
00264 failf(data, "necessary data rewind wasn't possible\n");
00265 return CURLE_SEND_FAIL_REWIND;
00266 }
00267 }
00268 return CURLE_OK;
00269 }
00270
00271 static int data_pending(struct connectdata *conn)
00272 {
00273
00274
00275 return conn->protocol&(PROT_SCP|PROT_SFTP) ||
00276 Curl_ssl_data_pending(conn, FIRSTSOCKET);
00277 }
00278
00279 #ifndef MIN
00280 #define MIN(a,b) (a < b ? a : b)
00281 #endif
00282
00283 static void read_rewind(struct connectdata *conn,
00284 size_t thismuch)
00285 {
00286 conn->read_pos -= thismuch;
00287 conn->bits.stream_was_rewound = TRUE;
00288
00289 #ifdef CURLDEBUG
00290 {
00291 char buf[512 + 1];
00292 size_t show;
00293
00294 show = MIN(conn->buf_len - conn->read_pos, sizeof(buf)-1);
00295 if (conn->master_buffer) {
00296 memcpy(buf, conn->master_buffer + conn->read_pos, show);
00297 buf[show] = '\0';
00298 }
00299 else {
00300 buf[0] = '\0';
00301 }
00302
00303 DEBUGF(infof(conn->data,
00304 "Buffer after stream rewind (read_pos = %d): [%s]",
00305 conn->read_pos, buf));
00306 }
00307 #endif
00308 }
00309
00310
00311
00312
00313
00314 CURLcode Curl_readwrite(struct connectdata *conn,
00315 bool *done)
00316 {
00317 struct SessionHandle *data = conn->data;
00318 struct Curl_transfer_keeper *k = &data->reqdata.keep;
00319 CURLcode result;
00320 ssize_t nread;
00321 int didwhat=0;
00322
00323 curl_socket_t fd_read;
00324 curl_socket_t fd_write;
00325 curl_off_t contentlength;
00326 int select_res = conn->cselect_bits;
00327
00328 conn->cselect_bits = 0;
00329
00330
00331
00332
00333 if((k->keepon & (KEEP_READ|KEEP_READ_HOLD)) == KEEP_READ)
00334 fd_read = conn->sockfd;
00335 else
00336 fd_read = CURL_SOCKET_BAD;
00337
00338 if((k->keepon & (KEEP_WRITE|KEEP_WRITE_HOLD)) == KEEP_WRITE)
00339 fd_write = conn->writesockfd;
00340 else
00341 fd_write = CURL_SOCKET_BAD;
00342
00343 if (!select_res) {
00344
00345 select_res = Curl_socket_ready(fd_read, fd_write, 0);
00346 }
00347
00348 if(select_res == CURL_CSELECT_ERR) {
00349 failf(data, "select/poll returned error");
00350 return CURLE_SEND_ERROR;
00351 }
00352
00353 do {
00354
00355
00356
00357 if((k->keepon & KEEP_READ) &&
00358 ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) {
00359
00360 bool is_empty_data = FALSE;
00361
00362
00363
00364 do {
00365 size_t buffersize = data->set.buffer_size?
00366 data->set.buffer_size : BUFSIZE;
00367 size_t bytestoread = buffersize;
00368 int readrc;
00369
00370 if (k->size != -1 && !k->header) {
00371
00372
00373
00374 curl_off_t totalleft = k->size - k->bytecount;
00375 if(totalleft < (curl_off_t)bytestoread)
00376 bytestoread = (size_t)totalleft;
00377 }
00378
00379
00380 readrc = Curl_read(conn, conn->sockfd, k->buf, bytestoread, &nread);
00381
00382
00383 if(0 > readrc)
00384 break;
00385
00386
00387 result = (CURLcode)readrc;
00388
00389 if(result>0)
00390 return result;
00391
00392 if ((k->bytecount == 0) && (k->writebytecount == 0)) {
00393 Curl_pgrsTime(data, TIMER_STARTTRANSFER);
00394 if(k->wait100_after_headers)
00395
00396 k->start100 = Curl_tvnow();
00397 }
00398
00399 didwhat |= KEEP_READ;
00400
00401 is_empty_data = (bool)((nread == 0) && (k->bodywrites == 0));
00402
00403
00404 if (0 < nread || is_empty_data) {
00405 k->buf[nread] = 0;
00406 }
00407 else if (0 >= nread) {
00408
00409
00410 DEBUGF(infof(data, "nread <= 0, server closed connection, bailing\n"));
00411 k->keepon &= ~KEEP_READ;
00412 break;
00413 }
00414
00415
00416
00417 k->str = k->buf;
00418
00419
00420
00421 if (k->header) {
00422
00423 bool stop_reading = FALSE;
00424
00425
00426 do {
00427 size_t hbufp_index;
00428 size_t rest_length;
00429 size_t full_length;
00430 int writetype;
00431
00432
00433 k->str_start = k->str;
00434
00435
00436 k->end_ptr = memchr(k->str_start, 0x0a, nread);
00437
00438 if (!k->end_ptr) {
00439
00440
00441
00442 if (k->hbuflen + nread >= data->state.headersize) {
00443
00444 char *newbuff;
00445 size_t newsize=CURLMAX((k->hbuflen+nread)*3/2,
00446 data->state.headersize*2);
00447 hbufp_index = k->hbufp - data->state.headerbuff;
00448 newbuff = (char *)realloc(data->state.headerbuff, newsize);
00449 if(!newbuff) {
00450 failf (data, "Failed to alloc memory for big header!");
00451 return CURLE_OUT_OF_MEMORY;
00452 }
00453 data->state.headersize=newsize;
00454 data->state.headerbuff = newbuff;
00455 k->hbufp = data->state.headerbuff + hbufp_index;
00456 }
00457 memcpy(k->hbufp, k->str, nread);
00458 k->hbufp += nread;
00459 k->hbuflen += nread;
00460 if (!k->headerline && (k->hbuflen>5)) {
00461
00462 if(!checkhttpprefix(data, data->state.headerbuff)) {
00463
00464 k->header = FALSE;
00465 k->badheader = HEADER_ALLBAD;
00466 break;
00467 }
00468 }
00469
00470 break;
00471 }
00472
00473
00474 rest_length = (k->end_ptr - k->str)+1;
00475 nread -= (ssize_t)rest_length;
00476
00477 k->str = k->end_ptr + 1;
00478
00479 full_length = k->str - k->str_start;
00480
00481
00482
00483
00484
00485
00486
00487 if (k->hbuflen + full_length >=
00488 data->state.headersize) {
00489 char *newbuff;
00490 size_t newsize=CURLMAX((k->hbuflen+full_length)*3/2,
00491 data->state.headersize*2);
00492 hbufp_index = k->hbufp - data->state.headerbuff;
00493 newbuff = (char *)realloc(data->state.headerbuff, newsize);
00494 if(!newbuff) {
00495 failf (data, "Failed to alloc memory for big header!");
00496 return CURLE_OUT_OF_MEMORY;
00497 }
00498 data->state.headersize= newsize;
00499 data->state.headerbuff = newbuff;
00500 k->hbufp = data->state.headerbuff + hbufp_index;
00501 }
00502
00503
00504 memcpy(k->hbufp, k->str_start, full_length);
00505 k->hbufp += full_length;
00506 k->hbuflen += full_length;
00507 *k->hbufp = 0;
00508 k->end_ptr = k->hbufp;
00509
00510 k->p = data->state.headerbuff;
00511
00512
00513
00514
00515
00516 if(!k->headerline) {
00517
00518 if((k->hbuflen>5) &&
00519 !checkhttpprefix(data, data->state.headerbuff)) {
00520
00521 k->header = FALSE;
00522 if(nread)
00523
00524 k->badheader = HEADER_PARTHEADER;
00525 else {
00526
00527 k->badheader = HEADER_ALLBAD;
00528 nread = (ssize_t)rest_length;
00529 }
00530 break;
00531 }
00532 }
00533
00534
00535
00536 if ((0x0a == *k->p) || (0x0d == *k->p)) {
00537 size_t headerlen;
00538
00539
00540 #ifdef CURL_DOES_CONVERSIONS
00541 if (0x0d == *k->p) {
00542 *k->p = '\r';
00543 k->p++;
00544 }
00545 if (0x0a == *k->p) {
00546 *k->p = '\n';
00547 k->p++;
00548 }
00549 #else
00550 if ('\r' == *k->p)
00551 k->p++;
00552 if ('\n' == *k->p)
00553 k->p++;
00554 #endif
00555
00556 if(100 == k->httpcode) {
00557
00558
00559
00560
00561
00562
00563
00564 k->header = TRUE;
00565 k->headerline = 0;
00566
00567 if (k->write_after_100_header) {
00568
00569 k->write_after_100_header = FALSE;
00570 k->keepon |= KEEP_WRITE;
00571 }
00572 }
00573 else {
00574 k->header = FALSE;
00575
00576 if((k->size == -1) && !conn->bits.chunk && !conn->bits.close &&
00577 (k->httpversion >= 11) ) {
00578
00579
00580
00581
00582
00583 infof(data, "no chunk, no close, no size. Assume close to "
00584 "signal end\n");
00585 conn->bits.close = TRUE;
00586 }
00587 }
00588
00589 if (417 == k->httpcode) {
00590
00591
00592
00593
00594
00595
00596 k->write_after_100_header = FALSE;
00597 k->keepon &= ~KEEP_WRITE;
00598 }
00599
00600 #ifndef CURL_DISABLE_HTTP
00601
00602
00603
00604
00605 if (Curl_http_should_fail(conn)) {
00606 failf (data, "The requested URL returned error: %d",
00607 k->httpcode);
00608 return CURLE_HTTP_RETURNED_ERROR;
00609 }
00610 #endif
00611
00612
00613
00614 writetype = CLIENTWRITE_HEADER;
00615 if (data->set.include_header)
00616 writetype |= CLIENTWRITE_BODY;
00617
00618 headerlen = k->p - data->state.headerbuff;
00619
00620 result = Curl_client_write(conn, writetype,
00621 data->state.headerbuff,
00622 headerlen);
00623 if(result)
00624 return result;
00625
00626 data->info.header_size += (long)headerlen;
00627 data->reqdata.keep.headerbytecount += (long)headerlen;
00628
00629 data->reqdata.keep.deductheadercount =
00630 (100 == k->httpcode)?data->reqdata.keep.headerbytecount:0;
00631
00632 if (data->reqdata.resume_from &&
00633 (data->set.httpreq==HTTPREQ_GET) &&
00634 (k->httpcode == 416)) {
00635
00636 stop_reading = TRUE;
00637 }
00638
00639 #ifndef CURL_DISABLE_HTTP
00640 if(!stop_reading) {
00641
00642
00643
00644 result = Curl_http_auth_act(conn);
00645
00646 if(result)
00647 return result;
00648
00649 if(conn->bits.rewindaftersend) {
00650
00651
00652 infof(data, "Keep sending data to get tossed away!\n");
00653 k->keepon |= KEEP_WRITE;
00654 }
00655 }
00656 #endif
00657
00658 if(!k->header) {
00659
00660
00661
00662
00663
00664
00665 if(conn->bits.no_body)
00666 stop_reading = TRUE;
00667 else {
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681 if(conn->bits.chunk)
00682 k->size=-1;
00683
00684 }
00685 if(-1 != k->size) {
00686
00687
00688
00689
00690 Curl_pgrsSetDownloadSize(data, k->size);
00691 k->maxdownload = k->size;
00692 }
00693
00694
00695 if(0 == k->maxdownload)
00696 stop_reading = TRUE;
00697
00698 if(stop_reading) {
00699
00700 k->keepon &= ~KEEP_READ;
00701 }
00702
00703 if(data->set.verbose)
00704 Curl_debug(data, CURLINFO_HEADER_IN,
00705 k->str_start, headerlen, conn);
00706 break;
00707 }
00708
00709
00710
00711 k->hbufp = data->state.headerbuff;
00712 k->hbuflen = 0;
00713 continue;
00714 }
00715
00716
00717
00718
00719
00720 if (!k->headerline++) {
00721
00722
00723 int httpversion_major;
00724 int nc;
00725 #ifdef CURL_DOES_CONVERSIONS
00726 #define HEADER1 scratch
00727 #define SCRATCHSIZE 21
00728 CURLcode res;
00729 char scratch[SCRATCHSIZE+1];
00730
00731
00732
00733
00734
00735 strncpy(&scratch[0], k->p, SCRATCHSIZE);
00736 scratch[SCRATCHSIZE] = 0;
00737 res = Curl_convert_from_network(data,
00738 &scratch[0],
00739 SCRATCHSIZE);
00740 if (CURLE_OK != res) {
00741
00742 return res;
00743 }
00744 #else
00745 #define HEADER1 k->p
00746 #endif
00747
00748 nc = sscanf(HEADER1,
00749 " HTTP/%d.%d %3d",
00750 &httpversion_major,
00751 &k->httpversion,
00752 &k->httpcode);
00753 if (nc==3) {
00754 k->httpversion += 10 * httpversion_major;
00755 }
00756 else {
00757
00758
00759
00760 nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode);
00761 k->httpversion = 10;
00762
00763
00764
00765
00766 if (!nc) {
00767 if (checkhttpprefix(data, k->p)) {
00768 nc = 1;
00769 k->httpcode = 200;
00770 k->httpversion = 10;
00771 }
00772 }
00773 }
00774
00775 if (nc) {
00776 data->info.httpcode = k->httpcode;
00777 data->info.httpversion = k->httpversion;
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787 if (data->set.http_fail_on_error && (k->httpcode >= 400) &&
00788 ((k->httpcode != 401) || !conn->bits.user_passwd) &&
00789 ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) {
00790
00791 if (data->reqdata.resume_from &&
00792 (data->set.httpreq==HTTPREQ_GET) &&
00793 (k->httpcode == 416)) {
00794
00795
00796 }
00797 else {
00798
00799 failf (data, "The requested URL returned error: %d",
00800 k->httpcode);
00801 return CURLE_HTTP_RETURNED_ERROR;
00802 }
00803 }
00804
00805 if(k->httpversion == 10) {
00806
00807
00808
00809 infof(data, "HTTP 1.0, assume close after body\n");
00810 conn->bits.close = TRUE;
00811 }
00812
00813 switch(k->httpcode) {
00814 case 204:
00815
00816
00817
00818
00819
00820
00821 case 416:
00822
00823
00824 case 304:
00825
00826
00827
00828
00829 k->size=0;
00830 k->maxdownload=0;
00831 k->ignorecl = TRUE;
00832 break;
00833 default:
00834
00835 break;
00836 }
00837 }
00838 else {
00839 k->header = FALSE;
00840 break;
00841 }
00842 }
00843
00844 #ifdef CURL_DOES_CONVERSIONS
00845
00846 result = Curl_convert_from_network(data, k->p, strlen(k->p));
00847 if (CURLE_OK != result) {
00848 return(result);
00849 }
00850
00851 #endif
00852
00853
00854
00855
00856
00857 if (!k->ignorecl && !data->set.ignorecl &&
00858 checkprefix("Content-Length:", k->p)) {
00859 contentlength = curlx_strtoofft(k->p+15, NULL, 10);
00860 if (data->set.max_filesize &&
00861 contentlength > data->set.max_filesize) {
00862 failf(data, "Maximum file size exceeded");
00863 return CURLE_FILESIZE_EXCEEDED;
00864 }
00865 if(contentlength >= 0) {
00866 k->size = contentlength;
00867 k->maxdownload = k->size;
00868 }
00869 else {
00870
00871
00872
00873 conn->bits.close = TRUE;
00874 infof(data, "Negative content-length: %" FORMAT_OFF_T
00875 ", closing after transfer\n", contentlength);
00876 }
00877 }
00878
00879 else if (checkprefix("Content-Type:", k->p)) {
00880 char *start;
00881 char *end;
00882 size_t len;
00883
00884
00885 for(start=k->p+13;
00886 *start && ISSPACE(*start);
00887 start++)
00888 ;
00889
00890
00891
00892 end = strchr(start, '\r');
00893 if(!end)
00894 end = strchr(start, '\n');
00895
00896 if(end) {
00897
00898 for(; ISSPACE(*end) && (end > start); end--)
00899 ;
00900
00901
00902 len = end-start+1;
00903
00904
00905 Curl_safefree(data->info.contenttype);
00906
00907 data->info.contenttype = malloc(len + 1);
00908 if (NULL == data->info.contenttype)
00909 return CURLE_OUT_OF_MEMORY;
00910
00911
00912 memcpy(data->info.contenttype, start, len);
00913 data->info.contenttype[len] = 0;
00914 }
00915 }
00916 #ifndef CURL_DISABLE_HTTP
00917 else if((k->httpversion == 10) &&
00918 conn->bits.httpproxy &&
00919 Curl_compareheader(k->p,
00920 "Proxy-Connection:", "keep-alive")) {
00921
00922
00923
00924
00925
00926
00927 conn->bits.close = FALSE;
00928 infof(data, "HTTP/1.0 proxy connection set to keep alive!\n");
00929 }
00930 else if((k->httpversion == 11) &&
00931 conn->bits.httpproxy &&
00932 Curl_compareheader(k->p,
00933 "Proxy-Connection:", "close")) {
00934
00935
00936
00937
00938 conn->bits.close = TRUE;
00939 infof(data, "HTTP/1.1 proxy connection set close!\n");
00940 }
00941 else if((k->httpversion == 10) &&
00942 Curl_compareheader(k->p, "Connection:", "keep-alive")) {
00943
00944
00945
00946
00947
00948
00949 conn->bits.close = FALSE;
00950 infof(data, "HTTP/1.0 connection set to keep alive!\n");
00951 }
00952 else if (Curl_compareheader(k->p, "Connection:", "close")) {
00953
00954
00955
00956
00957
00958
00959 conn->bits.close = TRUE;
00960 }
00961 else if (Curl_compareheader(k->p,
00962 "Transfer-Encoding:", "chunked")) {
00963
00964
00965
00966
00967
00968
00969
00970
00971 conn->bits.chunk = TRUE;
00972
00973
00974 Curl_httpchunk_init(conn);
00975 }
00976
00977 else if (checkprefix("Trailer:", k->p) ||
00978 checkprefix("Trailers:", k->p)) {
00979
00980
00981
00982
00983
00984
00985
00986
00987 conn->bits.trailerHdrPresent = TRUE;
00988 }
00989
00990 else if (checkprefix("Content-Encoding:", k->p) &&
00991 data->set.encoding) {
00992
00993
00994
00995
00996
00997
00998
00999 char *start;
01000
01001
01002 for(start=k->p+17;
01003 *start && ISSPACE(*start);
01004 start++)
01005 ;
01006
01007
01008 if (checkprefix("identity", start))
01009 k->content_encoding = IDENTITY;
01010 else if (checkprefix("deflate", start))
01011 k->content_encoding = DEFLATE;
01012 else if (checkprefix("gzip", start)
01013 || checkprefix("x-gzip", start))
01014 k->content_encoding = GZIP;
01015 else if (checkprefix("compress", start)
01016 || checkprefix("x-compress", start))
01017 k->content_encoding = COMPRESS;
01018 }
01019 else if (checkprefix("Content-Range:", k->p)) {
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029 char *ptr = k->p + 14;
01030
01031
01032 while(*ptr && !ISDIGIT(*ptr))
01033 ptr++;
01034
01035 k->offset = curlx_strtoofft(ptr, NULL, 10);
01036
01037 if (data->reqdata.resume_from == k->offset)
01038
01039 k->content_range = TRUE;
01040 }
01041 #if !defined(CURL_DISABLE_COOKIES)
01042 else if(data->cookies &&
01043 checkprefix("Set-Cookie:", k->p)) {
01044 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
01045 CURL_LOCK_ACCESS_SINGLE);
01046 Curl_cookie_add(data,
01047 data->cookies, TRUE, k->p+11,
01048
01049
01050 conn->allocptr.cookiehost?
01051 conn->allocptr.cookiehost:conn->host.name,
01052 data->reqdata.path);
01053 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
01054 }
01055 #endif
01056 else if(checkprefix("Last-Modified:", k->p) &&
01057 (data->set.timecondition || data->set.get_filetime) ) {
01058 time_t secs=time(NULL);
01059 k->timeofdoc = curl_getdate(k->p+strlen("Last-Modified:"),
01060 &secs);
01061 if(data->set.get_filetime)
01062 data->info.filetime = (long)k->timeofdoc;
01063 }
01064 else if((checkprefix("WWW-Authenticate:", k->p) &&
01065 (401 == k->httpcode)) ||
01066 (checkprefix("Proxy-authenticate:", k->p) &&
01067 (407 == k->httpcode))) {
01068 result = Curl_http_input_auth(conn, k->httpcode, k->p);
01069 if(result)
01070 return result;
01071 }
01072 else if ((k->httpcode >= 300 && k->httpcode < 400) &&
01073 checkprefix("Location:", k->p)) {
01074 if(data->set.http_follow_location) {
01075
01076 char *ptr;
01077 char *start=k->p;
01078 char backup;
01079
01080 start += 9;
01081
01082
01083
01084 while(*start && ISSPACE(*start ))
01085 start++;
01086
01087
01088
01089
01090
01091
01092 ptr = k->end_ptr-1;
01093 while((ptr>=start) && ISSPACE(*ptr))
01094 ptr--;
01095 ptr++;
01096
01097 backup = *ptr;
01098 if(ptr != start) {
01099 *ptr = '\0';
01100 data->reqdata.newurl = strdup(start);
01101 *ptr = backup;
01102 if(!data->reqdata.newurl)
01103 return CURLE_OUT_OF_MEMORY;
01104 }
01105 }
01106 }
01107 #endif
01108
01109
01110
01111
01112
01113 writetype = CLIENTWRITE_HEADER;
01114 if (data->set.include_header)
01115 writetype |= CLIENTWRITE_BODY;
01116
01117 if(data->set.verbose)
01118 Curl_debug(data, CURLINFO_HEADER_IN,
01119 k->p, (size_t)k->hbuflen, conn);
01120
01121 result = Curl_client_write(conn, writetype, k->p, k->hbuflen);
01122 if(result)
01123 return result;
01124
01125 data->info.header_size += (long)k->hbuflen;
01126 data->reqdata.keep.headerbytecount += (long)k->hbuflen;
01127
01128
01129 k->hbufp = data->state.headerbuff;
01130 k->hbuflen = 0;
01131 }
01132 while (!stop_reading && *k->str);
01133
01134 if(stop_reading)
01135
01136 break;
01137
01138
01139
01140
01141
01142 }
01143
01144
01145
01146
01147 if (k->str && !k->header && (nread > 0 || is_empty_data)) {
01148
01149 if(0 == k->bodywrites && !is_empty_data) {
01150
01151
01152 if(conn->protocol&PROT_HTTP) {
01153
01154
01155 if (data->reqdata.newurl) {
01156 if(conn->bits.close) {
01157
01158
01159 k->keepon &= ~KEEP_READ;
01160 *done = TRUE;
01161 return CURLE_OK;
01162 }
01163
01164
01165
01166 k->ignorebody = TRUE;
01167 infof(data, "Ignoring the response-body\n");
01168 }
01169 if (data->reqdata.resume_from && !k->content_range &&
01170 (data->set.httpreq==HTTPREQ_GET) &&
01171 !k->ignorebody) {
01172
01173
01174
01175 failf(data, "HTTP server doesn't seem to support "
01176 "byte ranges. Cannot resume.");
01177 return CURLE_HTTP_RANGE_ERROR;
01178 }
01179
01180 if(data->set.timecondition && !data->reqdata.range) {
01181
01182
01183
01184
01185 if((k->timeofdoc > 0) && (data->set.timevalue > 0)) {
01186 switch(data->set.timecondition) {
01187 case CURL_TIMECOND_IFMODSINCE:
01188 default:
01189 if(k->timeofdoc < data->set.timevalue) {
01190 infof(data,
01191 "The requested document is not new enough\n");
01192 *done = TRUE;
01193 return CURLE_OK;
01194 }
01195 break;
01196 case CURL_TIMECOND_IFUNMODSINCE:
01197 if(k->timeofdoc > data->set.timevalue) {
01198 infof(data,
01199 "The requested document is not old enough\n");
01200 *done = TRUE;
01201 return CURLE_OK;
01202 }
01203 break;
01204 }
01205 }
01206 }
01207
01208 }
01209 }
01210 k->bodywrites++;
01211
01212
01213 if(data->set.verbose) {
01214 if(k->badheader) {
01215 Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff,
01216 (size_t)k->hbuflen, conn);
01217 if(k->badheader == HEADER_PARTHEADER)
01218 Curl_debug(data, CURLINFO_DATA_IN,
01219 k->str, (size_t)nread, conn);
01220 }
01221 else
01222 Curl_debug(data, CURLINFO_DATA_IN,
01223 k->str, (size_t)nread, conn);
01224 }
01225
01226 #ifndef CURL_DISABLE_HTTP
01227 if(conn->bits.chunk) {
01228
01229
01230
01231
01232
01233
01234
01235 CHUNKcode res =
01236 Curl_httpchunk_read(conn, k->str, nread, &nread);
01237
01238 if(CHUNKE_OK < res) {
01239 if(CHUNKE_WRITE_ERROR == res) {
01240 failf(data, "Failed writing data");
01241 return CURLE_WRITE_ERROR;
01242 }
01243 failf(data, "Received problem %d in the chunky parser", res);
01244 return CURLE_RECV_ERROR;
01245 }
01246 else if(CHUNKE_STOP == res) {
01247 size_t dataleft;
01248
01249 k->keepon &= ~KEEP_READ;
01250
01251
01252
01253
01254
01255
01256
01257 dataleft = data->reqdata.proto.http->chunk.dataleft;
01258 if (dataleft != 0) {
01259 infof(conn->data, "Leftovers after chunking. "
01260 " Rewinding %d bytes\n",dataleft);
01261 read_rewind(conn, dataleft);
01262 }
01263 }
01264
01265 }
01266 #endif
01267
01268 if((-1 != k->maxdownload) &&
01269 (k->bytecount + nread >= k->maxdownload)) {
01270
01271
01272 size_t excess = (size_t)(k->bytecount + nread - k->maxdownload);
01273 if (excess > 0 && !k->ignorebody) {
01274 infof(data,
01275 "Rewinding stream by : %d"
01276 " bytes on url %s (size = %" FORMAT_OFF_T
01277 ", maxdownload = %" FORMAT_OFF_T
01278 ", bytecount = %" FORMAT_OFF_T ", nread = %d)\n",
01279 excess, conn->data->reqdata.path,
01280 k->size, k->maxdownload, k->bytecount, nread);
01281 read_rewind(conn, excess);
01282 }
01283
01284 nread = (ssize_t) (k->maxdownload - k->bytecount);
01285 if(nread < 0 )
01286 nread = 0;
01287
01288 k->keepon &= ~KEEP_READ;
01289 }
01290
01291 k->bytecount += nread;
01292
01293 Curl_pgrsSetDownloadCounter(data, k->bytecount);
01294
01295 if(!conn->bits.chunk && (nread || k->badheader || is_empty_data)) {
01296
01297
01298 if(k->badheader && !k->ignorebody) {
01299
01300
01301 result = Curl_client_write(conn, CLIENTWRITE_BODY,
01302 data->state.headerbuff,
01303 k->hbuflen);
01304 if(result)
01305 return result;
01306 }
01307 if(k->badheader < HEADER_ALLBAD) {
01308
01309
01310
01311
01312
01313 #ifdef HAVE_LIBZ
01314 switch (conn->data->set.http_ce_skip ?
01315 IDENTITY : k->content_encoding) {
01316 case IDENTITY:
01317 #endif
01318
01319
01320
01321 if(!k->ignorebody)
01322 result = Curl_client_write(conn, CLIENTWRITE_BODY, k->str,
01323 nread);
01324 #ifdef HAVE_LIBZ
01325 break;
01326
01327 case DEFLATE:
01328
01329 if(!k->ignorebody)
01330 result = Curl_unencode_deflate_write(conn, k, nread);
01331 break;
01332
01333 case GZIP:
01334
01335 if(!k->ignorebody)
01336 result = Curl_unencode_gzip_write(conn, k, nread);
01337 break;
01338
01339 case COMPRESS:
01340 default:
01341 failf (data, "Unrecognized content encoding type. "
01342 "libcurl understands `identity', `deflate' and `gzip' "
01343 "content encodings.");
01344 result = CURLE_BAD_CONTENT_ENCODING;
01345 break;
01346 }
01347 #endif
01348 }
01349 k->badheader = HEADER_NORMAL;
01350
01351 if(result)
01352 return result;
01353 }
01354
01355 }
01356
01357 if (is_empty_data) {
01358
01359
01360 k->keepon &= ~KEEP_READ;
01361 }
01362
01363 } while(data_pending(conn));
01364
01365 }
01366
01367
01368
01369 if((k->keepon & KEEP_WRITE) && (select_res & CURL_CSELECT_OUT)) {
01370
01371
01372 int i, si;
01373 ssize_t bytes_written;
01374 bool writedone=TRUE;
01375
01376 if ((k->bytecount == 0) && (k->writebytecount == 0))
01377 Curl_pgrsTime(data, TIMER_STARTTRANSFER);
01378
01379 didwhat |= KEEP_WRITE;
01380
01381
01382
01383
01384
01385 do {
01386
01387
01388
01389 if(0 == data->reqdata.upload_present) {
01390
01391 data->reqdata.upload_fromhere = k->uploadbuf;
01392
01393 if(!k->upload_done) {
01394
01395
01396 int fillcount;
01397
01398 if(k->wait100_after_headers &&
01399 (data->reqdata.proto.http->sending == HTTPSEND_BODY)) {
01400
01401
01402
01403 k->wait100_after_headers = FALSE;
01404 k->write_after_100_header = TRUE;
01405 k->keepon &= ~KEEP_WRITE;
01406 k->start100 = Curl_tvnow();
01407 didwhat &= ~KEEP_WRITE;
01408 break;
01409 }
01410
01411 result = Curl_fillreadbuffer(conn, BUFSIZE, &fillcount);
01412 if(result)
01413 return result;
01414
01415 nread = (ssize_t)fillcount;
01416 }
01417 else
01418 nread = 0;
01419
01420
01421
01422 if (nread<=0) {
01423
01424 k->keepon &= ~KEEP_WRITE;
01425 writedone = TRUE;
01426
01427 if(conn->bits.rewindaftersend) {
01428 result = Curl_readrewind(conn);
01429 if(result)
01430 return result;
01431 }
01432 break;
01433 }
01434
01435
01436 data->reqdata.upload_present = nread;
01437
01438
01439 #ifdef CURL_DO_LINEEND_CONV
01440
01441 if ((data->set.crlf) || (data->set.prefer_ascii)) {
01442 #else
01443 if (data->set.crlf) {
01444 #endif
01445 if(data->state.scratch == NULL)
01446 data->state.scratch = malloc(2*BUFSIZE);
01447 if(data->state.scratch == NULL) {
01448 failf (data, "Failed to alloc scratch buffer!");
01449 return CURLE_OUT_OF_MEMORY;
01450 }
01451
01452
01453
01454
01455
01456
01457 for(i = 0, si = 0; i < nread; i++, si++) {
01458 if (data->reqdata.upload_fromhere[i] == 0x0a) {
01459 data->state.scratch[si++] = 0x0d;
01460 data->state.scratch[si] = 0x0a;
01461 if (!data->set.crlf) {
01462
01463
01464 data->set.infilesize++;
01465 }
01466 }
01467 else
01468 data->state.scratch[si] = data->reqdata.upload_fromhere[i];
01469 }
01470 if(si != nread) {
01471
01472
01473 nread = si;
01474
01475
01476 data->reqdata.upload_fromhere = data->state.scratch;
01477
01478
01479 data->reqdata.upload_present = nread;
01480 }
01481 }
01482 }
01483 else {
01484
01485
01486 }
01487
01488
01489 result = Curl_write(conn,
01490 conn->writesockfd,
01491 data->reqdata.upload_fromhere,
01492 data->reqdata.upload_present,
01493 &bytes_written);
01494 if(result)
01495 return result;
01496
01497 if(data->set.verbose)
01498
01499 Curl_debug(data, CURLINFO_DATA_OUT, data->reqdata.upload_fromhere,
01500 (size_t)bytes_written, conn);
01501
01502 if(data->reqdata.upload_present != bytes_written) {
01503
01504
01505
01506 data->reqdata.upload_present -= bytes_written;
01507
01508
01509
01510 data->reqdata.upload_fromhere += bytes_written;
01511
01512 writedone = TRUE;
01513 }
01514 else {
01515
01516 data->reqdata.upload_fromhere = k->uploadbuf;
01517 data->reqdata.upload_present = 0;
01518
01519 if(k->upload_done) {
01520
01521 k->keepon &= ~KEEP_WRITE;
01522 writedone = TRUE;
01523 }
01524 }
01525
01526 k->writebytecount += bytes_written;
01527 Curl_pgrsSetUploadCounter(data, k->writebytecount);
01528
01529 } while(!writedone);
01530
01531 }
01532
01533 } while(0);
01534
01535 k->now = Curl_tvnow();
01536 if(didwhat) {
01537
01538 if(k->bytecountp)
01539 *k->bytecountp = k->bytecount;
01540 if(k->writebytecountp)
01541 *k->writebytecountp = k->writebytecount;
01542 }
01543 else {
01544
01545 if (k->write_after_100_header) {
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559 long ms = Curl_tvdiff(k->now, k->start100);
01560 if(ms > CURL_TIMEOUT_EXPECT_100) {
01561
01562 k->write_after_100_header = FALSE;
01563 k->keepon |= KEEP_WRITE;
01564 }
01565 }
01566 }
01567
01568 if(Curl_pgrsUpdate(conn))
01569 result = CURLE_ABORTED_BY_CALLBACK;
01570 else
01571 result = Curl_speedcheck(data, k->now);
01572 if (result)
01573 return result;
01574
01575 if (data->set.timeout &&
01576 (Curl_tvdiff(k->now, k->start) >= data->set.timeout)) {
01577 if (k->size != -1) {
01578 failf(data, "Operation timed out after %ld milliseconds with %"
01579 FORMAT_OFF_T " out of %" FORMAT_OFF_T " bytes received",
01580 data->set.timeout, k->bytecount, k->size);
01581 } else {
01582 failf(data, "Operation timed out after %ld milliseconds with %"
01583 FORMAT_OFF_T " bytes received",
01584 data->set.timeout, k->bytecount);
01585 }
01586 return CURLE_OPERATION_TIMEOUTED;
01587 }
01588
01589 if(!k->keepon) {
01590
01591
01592
01593
01594
01595 if(!(conn->bits.no_body) && (k->size != -1) &&
01596 (k->bytecount != k->size) &&
01597 #ifdef CURL_DO_LINEEND_CONV
01598
01599
01600
01601
01602 (k->bytecount != (k->size + data->state.crlf_conversions)) &&
01603 #endif
01604 !data->reqdata.newurl) {
01605 failf(data, "transfer closed with %" FORMAT_OFF_T
01606 " bytes remaining to read",
01607 k->size - k->bytecount);
01608 return CURLE_PARTIAL_FILE;
01609 }
01610 else if(!(conn->bits.no_body) &&
01611 conn->bits.chunk &&
01612 (data->reqdata.proto.http->chunk.state != CHUNK_STOP)) {
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622 failf(data, "transfer closed with outstanding read data remaining");
01623 return CURLE_PARTIAL_FILE;
01624 }
01625 if(Curl_pgrsUpdate(conn))
01626 return CURLE_ABORTED_BY_CALLBACK;
01627 }
01628
01629
01630 *done = (bool)(0 == (k->keepon&(KEEP_READ|KEEP_WRITE)));
01631
01632 return CURLE_OK;
01633 }
01634
01635
01636
01637
01638
01639
01640
01641 CURLcode Curl_readwrite_init(struct connectdata *conn)
01642 {
01643 struct SessionHandle *data = conn->data;
01644 struct Curl_transfer_keeper *k = &data->reqdata.keep;
01645
01646
01647
01648 memset(k, 0, sizeof(struct Curl_transfer_keeper));
01649
01650 k->start = Curl_tvnow();
01651 k->now = k->start;
01652 k->header = TRUE;
01653 k->httpversion = -1;
01654
01655 k->size = data->reqdata.size;
01656 k->maxdownload = data->reqdata.maxdownload;
01657 k->bytecountp = data->reqdata.bytecountp;
01658 k->writebytecountp = data->reqdata.writebytecountp;
01659
01660 k->bytecount = 0;
01661
01662 k->buf = data->state.buffer;
01663 k->uploadbuf = data->state.uploadbuffer;
01664 k->maxfd = (conn->sockfd>conn->writesockfd?
01665 conn->sockfd:conn->writesockfd)+1;
01666 k->hbufp = data->state.headerbuff;
01667 k->ignorebody=FALSE;
01668
01669 Curl_pgrsTime(data, TIMER_PRETRANSFER);
01670 Curl_speedinit(data);
01671
01672 Curl_pgrsSetUploadCounter(data, 0);
01673 Curl_pgrsSetDownloadCounter(data, 0);
01674
01675 if (!conn->bits.getheader) {
01676 k->header = FALSE;
01677 if(k->size > 0)
01678 Curl_pgrsSetDownloadSize(data, k->size);
01679 }
01680
01681 if(conn->bits.getheader || !conn->bits.no_body) {
01682
01683 if(conn->sockfd != CURL_SOCKET_BAD) {
01684 k->keepon |= KEEP_READ;
01685 }
01686
01687 if(conn->writesockfd != CURL_SOCKET_BAD) {
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697 if (data->state.expect100header &&
01698 (data->reqdata.proto.http->sending == HTTPSEND_BODY)) {
01699
01700 k->write_after_100_header = TRUE;
01701 k->start100 = k->start;
01702 }
01703 else {
01704 if(data->state.expect100header)
01705
01706
01707 k->wait100_after_headers = TRUE;
01708 k->keepon |= KEEP_WRITE;
01709 }
01710 }
01711 }
01712
01713 return CURLE_OK;
01714 }
01715
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725 void Curl_pre_readwrite(struct connectdata *conn)
01726 {
01727 conn->bits.chunk=FALSE;
01728 conn->bits.trailerHdrPresent=FALSE;
01729 }
01730
01731
01732
01733
01734
01735
01736
01737
01738 int Curl_single_getsock(struct connectdata *conn,
01739 curl_socket_t *sock,
01740
01741 int numsocks)
01742 {
01743 struct SessionHandle *data = conn->data;
01744 int bitmap = GETSOCK_BLANK;
01745 int index = 0;
01746
01747 if(numsocks < 2)
01748
01749 return GETSOCK_BLANK;
01750
01751 if(data->reqdata.keep.keepon & KEEP_READ) {
01752 bitmap |= GETSOCK_READSOCK(index);
01753 sock[index] = conn->sockfd;
01754 }
01755
01756 if(data->reqdata.keep.keepon & KEEP_WRITE) {
01757
01758 if((conn->sockfd != conn->writesockfd) ||
01759 !(data->reqdata.keep.keepon & KEEP_READ)) {
01760
01761
01762 if(data->reqdata.keep.keepon & KEEP_READ)
01763 index++;
01764 sock[index] = conn->writesockfd;
01765 }
01766
01767 bitmap |= GETSOCK_WRITESOCK(index);
01768 }
01769
01770 return bitmap;
01771 }
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788 static CURLcode
01789 Transfer(struct connectdata *conn)
01790 {
01791 CURLcode result;
01792 struct SessionHandle *data = conn->data;
01793 struct Curl_transfer_keeper *k = &data->reqdata.keep;
01794 bool done=FALSE;
01795
01796 if(!(conn->protocol & (PROT_FILE|PROT_TFTP))) {
01797
01798
01799
01800
01801 Curl_readwrite_init(conn);
01802 Curl_pre_readwrite(conn);
01803 }
01804
01805 if((conn->sockfd == CURL_SOCKET_BAD) &&
01806 (conn->writesockfd == CURL_SOCKET_BAD))
01807
01808 return CURLE_OK;
01809
01810
01811 if(!conn->bits.getheader && conn->bits.no_body)
01812 return CURLE_OK;
01813
01814 while (!done) {
01815 curl_socket_t fd_read;
01816 curl_socket_t fd_write;
01817
01818
01819
01820
01821 if ((k->keepon & KEEP_WRITE) &&
01822 (!data->set.max_send_speed ||
01823 (data->progress.ulspeed < data->set.max_send_speed) )) {
01824 fd_write = conn->writesockfd;
01825 k->keepon &= ~KEEP_WRITE_HOLD;
01826 }
01827 else {
01828 fd_write = CURL_SOCKET_BAD;
01829 if(k->keepon & KEEP_WRITE)
01830 k->keepon |= KEEP_WRITE_HOLD;
01831 }
01832
01833 if ((k->keepon & KEEP_READ) &&
01834 (!data->set.max_recv_speed ||
01835 (data->progress.dlspeed < data->set.max_recv_speed)) ) {
01836 fd_read = conn->sockfd;
01837 k->keepon &= ~KEEP_READ_HOLD;
01838 }
01839 else {
01840 fd_read = CURL_SOCKET_BAD;
01841 if(k->keepon & KEEP_READ)
01842 k->keepon |= KEEP_READ_HOLD;
01843 }
01844
01845
01846
01847
01848
01849
01850 switch (Curl_socket_ready(fd_read, fd_write, 1000)) {
01851 case -1:
01852 #ifdef EINTR
01853
01854
01855 if(SOCKERRNO == EINTR)
01856 ;
01857 else
01858 #endif
01859 done = TRUE;
01860 continue;
01861 case 0:
01862 default:
01863
01864 result = Curl_readwrite(conn, &done);
01865 break;
01866 }
01867 if(result)
01868 return result;
01869
01870
01871 }
01872
01873 return CURLE_OK;
01874 }
01875
01876
01877
01878
01879 CURLcode Curl_pretransfer(struct SessionHandle *data)
01880 {
01881 CURLcode res;
01882 if(!data->change.url) {
01883
01884 failf(data, "No URL set!\n");
01885 return CURLE_URL_MALFORMAT;
01886 }
01887
01888
01889
01890
01891 res = Curl_ssl_initsessions(data, data->set.ssl.numsessions);
01892 if(res)
01893 return res;
01894
01895 data->set.followlocation=0;
01896 data->state.this_is_a_follow = FALSE;
01897 data->state.errorbuf = FALSE;
01898
01899 data->state.authproblem = FALSE;
01900 data->state.authhost.want = data->set.httpauth;
01901 data->state.authproxy.want = data->set.proxyauth;
01902
01903
01904 if(data->change.cookielist) {
01905 Curl_cookie_loadfiles(data);
01906 }
01907
01908
01909
01910
01911 data->state.allow_port = TRUE;
01912
01913 #if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
01914
01915
01916
01917 if(!data->set.no_signal)
01918 data->state.prev_signal = signal(SIGPIPE, SIG_IGN);
01919 #endif
01920
01921 Curl_initinfo(data);
01922 Curl_pgrsStartNow(data);
01923
01924 return CURLE_OK;
01925 }
01926
01927
01928
01929
01930 CURLcode Curl_posttransfer(struct SessionHandle *data)
01931 {
01932 #if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
01933
01934 if(!data->set.no_signal)
01935 signal(SIGPIPE, data->state.prev_signal);
01936 #else
01937 (void)data;
01938 #endif
01939
01940 if(!(data->progress.flags & PGRS_HIDE) &&
01941 !data->progress.callback)
01942
01943 fprintf(data->set.err, "\n");
01944
01945 return CURLE_OK;
01946 }
01947
01948
01949
01950
01951
01952 static int strlen_url(char *url)
01953 {
01954 char *ptr;
01955 int newlen=0;
01956 bool left=TRUE;
01957
01958 for(ptr=url; *ptr; ptr++) {
01959 switch(*ptr) {
01960 case '?':
01961 left=FALSE;
01962 default:
01963 newlen++;
01964 break;
01965 case ' ':
01966 if(left)
01967 newlen+=3;
01968 else
01969 newlen++;
01970 break;
01971 }
01972 }
01973 return newlen;
01974 }
01975
01976
01977
01978
01979 static void strcpy_url(char *output, char *url)
01980 {
01981
01982 bool left=TRUE;
01983 char *iptr;
01984 char *optr = output;
01985 for(iptr = url;
01986 *iptr;
01987 iptr++) {
01988 switch(*iptr) {
01989 case '?':
01990 left=FALSE;
01991 default:
01992 *optr++=*iptr;
01993 break;
01994 case ' ':
01995 if(left) {
01996 *optr++='%';
01997 *optr++='2';
01998 *optr++='0';
01999 }
02000 else
02001 *optr++='+';
02002 break;
02003 }
02004 }
02005 *optr=0;
02006
02007 }
02008
02009
02010
02011
02012
02013 CURLcode Curl_follow(struct SessionHandle *data,
02014 char *newurl,
02015
02016
02017 bool retry)
02018
02019 {
02020
02021 char prot[16];
02022 char letter;
02023 size_t newlen;
02024 char *newest;
02025
02026 if(!retry) {
02027 if ((data->set.maxredirs != -1) &&
02028 (data->set.followlocation >= data->set.maxredirs)) {
02029 failf(data,"Maximum (%d) redirects followed", data->set.maxredirs);
02030 return CURLE_TOO_MANY_REDIRECTS;
02031 }
02032
02033
02034 data->state.this_is_a_follow = TRUE;
02035
02036 data->set.followlocation++;
02037 }
02038
02039 if(data->set.http_auto_referer) {
02040
02041
02042
02043
02044 if(data->change.referer_alloc)
02045
02046 free(data->change.referer);
02047
02048 data->change.referer = strdup(data->change.url);
02049 data->change.referer_alloc = TRUE;
02050 }
02051
02052 if(2 != sscanf(newurl, "%15[^?&/:]://%c", prot, &letter)) {
02053
02054
02055
02056
02057
02058
02059
02060
02061 char *protsep;
02062 char *pathsep;
02063
02064 char *useurl = newurl;
02065 size_t urllen;
02066
02067
02068
02069 char *url_clone=strdup(data->change.url);
02070
02071 if(!url_clone)
02072 return CURLE_OUT_OF_MEMORY;
02073
02074
02075 protsep=strstr(url_clone, "//");
02076 if(!protsep)
02077 protsep=url_clone;
02078 else
02079 protsep+=2;
02080
02081 if('/' != newurl[0]) {
02082 int level=0;
02083
02084
02085
02086 pathsep = strchr(protsep, '?');
02087 if(pathsep)
02088 *pathsep=0;
02089
02090
02091
02092 pathsep = strrchr(protsep, '/');
02093 if(pathsep)
02094 *pathsep=0;
02095
02096
02097
02098 pathsep = strchr(protsep, '/');
02099 if(pathsep)
02100 protsep = pathsep+1;
02101 else
02102 protsep = NULL;
02103
02104
02105
02106
02107 if((useurl[0] == '.') && (useurl[1] == '/'))
02108 useurl+=2;
02109
02110 while((useurl[0] == '.') &&
02111 (useurl[1] == '.') &&
02112 (useurl[2] == '/')) {
02113 level++;
02114 useurl+=3;
02115 }
02116
02117 if(protsep) {
02118 while(level--) {
02119
02120 pathsep = strrchr(protsep, '/');
02121 if(pathsep)
02122 *pathsep=0;
02123 else {
02124 *protsep=0;
02125 break;
02126 }
02127 }
02128 }
02129 }
02130 else {
02131
02132
02133 pathsep = strchr(protsep, '/');
02134 if(pathsep) {
02135
02136
02137
02138 char *sep = strchr(protsep, '?');
02139 if(sep && (sep < pathsep))
02140 pathsep = sep;
02141 *pathsep=0;
02142 }
02143 else {
02144
02145
02146
02147
02148 pathsep = strchr(protsep, '?');
02149 if(pathsep)
02150 *pathsep=0;
02151 }
02152 }
02153
02154
02155
02156
02157
02158
02159 newlen = strlen_url(useurl);
02160
02161 urllen = strlen(url_clone);
02162
02163 newest=(char *)malloc( urllen + 1 +
02164 newlen + 1 );
02165
02166 if(!newest) {
02167 free(url_clone);
02168 return CURLE_OUT_OF_MEMORY;
02169 }
02170
02171
02172 memcpy(newest, url_clone, urllen);
02173
02174
02175 if(('/' == useurl[0]) || (protsep && !*protsep))
02176 ;
02177 else
02178 newest[urllen++]='/';
02179
02180
02181 strcpy_url(&newest[urllen], useurl);
02182
02183 free(newurl);
02184 free(url_clone);
02185 newurl = newest;
02186 }
02187 else {
02188
02189 data->state.allow_port = FALSE;
02190
02191 if(strchr(newurl, ' ')) {
02192
02193
02194 newlen = strlen_url(newurl);
02195
02196 newest = malloc(newlen+1);
02197 if(newest) {
02198 strcpy_url(newest, newurl);
02199
02200 free(newurl);
02201 newurl = newest;
02202 }
02203 }
02204
02205 }
02206
02207 if(data->change.url_alloc)
02208 free(data->change.url);
02209 else
02210 data->change.url_alloc = TRUE;
02211
02212 data->change.url = newurl;
02213 newurl = NULL;
02214
02215 infof(data, "Issue another request to this URL: '%s'\n", data->change.url);
02216
02217
02218
02219
02220
02221
02222
02223
02224 switch(data->info.httpcode) {
02225
02226
02227
02228
02229
02230
02231
02232 default:
02233
02234
02235
02236 break;
02237 case 301:
02238
02239
02240
02241
02242
02243
02244
02245
02246
02247
02248
02249
02250
02251
02252 if( data->set.httpreq == HTTPREQ_POST
02253 || data->set.httpreq == HTTPREQ_POST_FORM) {
02254 infof(data,
02255 "Violate RFC 2616/10.3.2 and switch from POST to GET\n");
02256 data->set.httpreq = HTTPREQ_GET;
02257 }
02258 break;
02259 case 302:
02260
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277 case 303:
02278
02279
02280 if(data->set.httpreq != HTTPREQ_GET) {
02281 data->set.httpreq = HTTPREQ_GET;
02282 infof(data, "Disables POST, goes with %s\n",
02283 data->set.opt_no_body?"HEAD":"GET");
02284 }
02285 break;
02286 case 304:
02287
02288
02289
02290 break;
02291 case 305:
02292
02293
02294
02295
02296
02297
02298
02299 break;
02300 }
02301 Curl_pgrsTime(data, TIMER_REDIRECT);
02302 Curl_pgrsResetTimes(data);
02303
02304 return CURLE_OK;
02305 }
02306
02307 static CURLcode
02308 Curl_connect_host(struct SessionHandle *data,
02309 struct connectdata **conn)
02310 {
02311 CURLcode res = CURLE_OK;
02312 int urlchanged = FALSE;
02313
02314 do {
02315 bool async;
02316 bool protocol_done=TRUE;
02317
02318 Curl_pgrsTime(data, TIMER_STARTSINGLE);
02319 data->change.url_changed = FALSE;
02320 res = Curl_connect(data, conn, &async, &protocol_done);
02321
02322 if((CURLE_OK == res) && async) {
02323
02324
02325 res = Curl_wait_for_resolv(*conn, NULL);
02326 if(CURLE_OK == res)
02327
02328 res = Curl_async_resolved(*conn, &protocol_done);
02329 else
02330
02331 (void)Curl_disconnect(*conn);
02332 }
02333 if(res)
02334 break;
02335
02336
02337
02338
02339 urlchanged = data->change.url_changed;
02340 if ((CURLE_OK == res) && urlchanged) {
02341 res = Curl_done(conn, res, FALSE);
02342 if(CURLE_OK == res) {
02343 char *gotourl = strdup(data->change.url);
02344 res = Curl_follow(data, gotourl, FALSE);
02345 if(res)
02346 free(gotourl);
02347 }
02348 }
02349 } while (urlchanged && res == CURLE_OK);
02350
02351 return res;
02352 }
02353
02354
02355 bool Curl_retry_request(struct connectdata *conn,
02356 char **url)
02357 {
02358 bool retry = FALSE;
02359 struct SessionHandle *data = conn->data;
02360
02361 if((data->reqdata.keep.bytecount +
02362 data->reqdata.keep.headerbytecount == 0) &&
02363 conn->bits.reuse &&
02364 !conn->bits.no_body) {
02365
02366
02367
02368
02369 infof(conn->data, "Connection died, retrying a fresh connect\n");
02370 *url = strdup(conn->data->change.url);
02371
02372 conn->bits.close = TRUE;
02373 conn->bits.retry = TRUE;
02374
02375
02376
02377
02378 retry = TRUE;
02379 }
02380
02381 return retry;
02382 }
02383
02384
02385
02386
02387
02388
02389 CURLcode Curl_perform(struct SessionHandle *data)
02390 {
02391 CURLcode res;
02392 CURLcode res2;
02393 struct connectdata *conn=NULL;
02394 char *newurl = NULL;
02395 bool retry = FALSE;
02396
02397 data->state.used_interface = Curl_if_easy;
02398
02399 res = Curl_pretransfer(data);
02400 if(res)
02401 return res;
02402
02403
02404
02405
02406
02407
02408
02409
02410 do {
02411 res = Curl_connect_host(data, &conn);
02412
02413 if(res == CURLE_OK) {
02414 bool do_done;
02415 if(data->set.connect_only) {
02416
02417 conn->bits.close = FALSE;
02418 res = Curl_done(&conn, CURLE_OK, FALSE);
02419 break;
02420 }
02421 res = Curl_do(&conn, &do_done);
02422
02423 if(res == CURLE_OK) {
02424 res = Transfer(conn);
02425 if(res == CURLE_OK) {
02426 retry = Curl_retry_request(conn, &newurl);
02427
02428 if(!retry)
02429
02430
02431
02432
02433 newurl = data->reqdata.newurl?strdup(data->reqdata.newurl):NULL;
02434 }
02435 else {
02436
02437
02438
02439 conn->bits.close = TRUE;
02440
02441 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
02442
02443
02444 sclose(conn->sock[SECONDARYSOCKET]);
02445 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
02446 }
02447 }
02448
02449
02450
02451 res2 = Curl_done(&conn, res, FALSE);
02452
02453 if(CURLE_OK == res)
02454 res = res2;
02455 }
02456 else
02457
02458 res2 = Curl_done(&conn, res, FALSE);
02459
02460
02461
02462
02463
02464
02465 if((res == CURLE_OK) && newurl) {
02466 res = Curl_follow(data, newurl, retry);
02467 if(CURLE_OK == res) {
02468 newurl = NULL;
02469 continue;
02470 }
02471 }
02472 }
02473 break;
02474
02475 } while(1);
02476
02477 if(newurl)
02478 free(newurl);
02479
02480 if(res && !data->state.errorbuf) {
02481
02482
02483
02484
02485
02486 const char *str = curl_easy_strerror(res);
02487 if(!str)
02488 failf(data, "unspecified error %d", (int)res);
02489 else
02490 failf(data, "%s", str);
02491 }
02492
02493
02494
02495 res2 = Curl_posttransfer(data);
02496 if(!res && res2)
02497 res = res2;
02498
02499 return res;
02500 }
02501
02502
02503
02504
02505
02506 CURLcode
02507 Curl_setup_transfer(
02508 struct connectdata *c_conn,
02509 int sockindex,
02510 curl_off_t size,
02511 bool getheader,
02512 curl_off_t *bytecountp,
02513 int writesockindex,
02514
02515
02516 curl_off_t *writecountp
02517
02518 )
02519 {
02520 struct connectdata *conn = (struct connectdata *)c_conn;
02521 struct SessionHandle *data;
02522
02523 if(!conn)
02524 return CURLE_BAD_FUNCTION_ARGUMENT;
02525
02526 data = conn->data;
02527
02528 DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
02529
02530
02531 conn->sockfd = sockindex == -1 ?
02532 CURL_SOCKET_BAD : conn->sock[sockindex];
02533 conn->writesockfd = writesockindex == -1 ?
02534 CURL_SOCKET_BAD:conn->sock[writesockindex];
02535 conn->bits.getheader = getheader;
02536
02537 data->reqdata.size = size;
02538 data->reqdata.bytecountp = bytecountp;
02539 data->reqdata.writebytecountp = writecountp;
02540
02541 return CURLE_OK;
02542 }