00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "curl_setup.h"
00024
00025 #include <curl/curl.h>
00026
00027 #include "urldata.h"
00028 #include "sendf.h"
00029 #include "connect.h"
00030 #include "vtls/vtls.h"
00031 #include "ssh.h"
00032 #include "multiif.h"
00033 #include "non-ascii.h"
00034 #include "strerror.h"
00035 #include "select.h"
00036
00037
00038 #include "curl_printf.h"
00039 #include "curl_memory.h"
00040 #include "memdebug.h"
00041
00042 #ifdef CURL_DO_LINEEND_CONV
00043
00044
00045
00046
00047
00048
00049 static size_t convert_lineends(struct Curl_easy *data,
00050 char *startPtr, size_t size)
00051 {
00052 char *inPtr, *outPtr;
00053
00054
00055 if((startPtr == NULL) || (size < 1)) {
00056 return size;
00057 }
00058
00059 if(data->state.prev_block_had_trailing_cr) {
00060
00061
00062 if(*startPtr == '\n') {
00063
00064
00065 memmove(startPtr, startPtr+1, size-1);
00066 size--;
00067
00068 data->state.crlf_conversions++;
00069 }
00070 data->state.prev_block_had_trailing_cr = FALSE;
00071 }
00072
00073
00074 inPtr = outPtr = memchr(startPtr, '\r', size);
00075 if(inPtr) {
00076
00077 while(inPtr < (startPtr+size-1)) {
00078
00079 if(memcmp(inPtr, "\r\n", 2) == 0) {
00080
00081 inPtr++;
00082 *outPtr = *inPtr;
00083
00084 data->state.crlf_conversions++;
00085 }
00086 else {
00087 if(*inPtr == '\r') {
00088
00089 *outPtr = '\n';
00090 }
00091 else {
00092
00093 *outPtr = *inPtr;
00094 }
00095 }
00096 outPtr++;
00097 inPtr++;
00098 }
00099
00100 if(inPtr < startPtr+size) {
00101
00102 if(*inPtr == '\r') {
00103
00104 *outPtr = '\n';
00105
00106 data->state.prev_block_had_trailing_cr = TRUE;
00107 }
00108 else {
00109
00110 *outPtr = *inPtr;
00111 }
00112 outPtr++;
00113 }
00114 if(outPtr < startPtr+size)
00115
00116 *outPtr = '\0';
00117
00118 return (outPtr - startPtr);
00119 }
00120 return size;
00121 }
00122 #endif
00123
00124 #ifdef USE_RECV_BEFORE_SEND_WORKAROUND
00125 bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
00126 {
00127 struct postponed_data * const psnd = &(conn->postponed[sockindex]);
00128 return psnd->buffer && psnd->allocated_size &&
00129 psnd->recv_size > psnd->recv_processed;
00130 }
00131
00132 static void pre_receive_plain(struct connectdata *conn, int num)
00133 {
00134 const curl_socket_t sockfd = conn->sock[num];
00135 struct postponed_data * const psnd = &(conn->postponed[num]);
00136 size_t bytestorecv = psnd->allocated_size - psnd->recv_size;
00137
00138
00139
00140
00141
00142 if((conn->handler->protocol&PROTO_FAMILY_HTTP) != 0 &&
00143 conn->recv[num] == Curl_recv_plain &&
00144 (!psnd->buffer || bytestorecv)) {
00145 const int readymask = Curl_socket_check(sockfd, CURL_SOCKET_BAD,
00146 CURL_SOCKET_BAD, 0);
00147 if(readymask != -1 && (readymask & CURL_CSELECT_IN) != 0) {
00148
00149 if(!psnd->buffer) {
00150
00151 psnd->allocated_size = 2 * BUFSIZE;
00152 psnd->buffer = malloc(psnd->allocated_size);
00153 psnd->recv_size = 0;
00154 psnd->recv_processed = 0;
00155 #ifdef DEBUGBUILD
00156 psnd->bindsock = sockfd;
00157 #endif
00158 bytestorecv = psnd->allocated_size;
00159 }
00160 if(psnd->buffer) {
00161 ssize_t recvedbytes;
00162 DEBUGASSERT(psnd->bindsock == sockfd);
00163 recvedbytes = sread(sockfd, psnd->buffer + psnd->recv_size,
00164 bytestorecv);
00165 if(recvedbytes > 0)
00166 psnd->recv_size += recvedbytes;
00167 }
00168 else
00169 psnd->allocated_size = 0;
00170 }
00171 }
00172 }
00173
00174 static ssize_t get_pre_recved(struct connectdata *conn, int num, char *buf,
00175 size_t len)
00176 {
00177 struct postponed_data * const psnd = &(conn->postponed[num]);
00178 size_t copysize;
00179 if(!psnd->buffer)
00180 return 0;
00181
00182 DEBUGASSERT(psnd->allocated_size > 0);
00183 DEBUGASSERT(psnd->recv_size <= psnd->allocated_size);
00184 DEBUGASSERT(psnd->recv_processed <= psnd->recv_size);
00185
00186
00187 if(psnd->recv_size > psnd->recv_processed) {
00188 DEBUGASSERT(psnd->bindsock == conn->sock[num]);
00189 copysize = CURLMIN(len, psnd->recv_size - psnd->recv_processed);
00190 memcpy(buf, psnd->buffer + psnd->recv_processed, copysize);
00191 psnd->recv_processed += copysize;
00192 }
00193 else
00194 copysize = 0;
00195
00196
00197 if(psnd->recv_processed == psnd->recv_size) {
00198 free(psnd->buffer);
00199 psnd->buffer = NULL;
00200 psnd->allocated_size = 0;
00201 psnd->recv_size = 0;
00202 psnd->recv_processed = 0;
00203 #ifdef DEBUGBUILD
00204 psnd->bindsock = CURL_SOCKET_BAD;
00205 #endif
00206 }
00207 return (ssize_t)copysize;
00208 }
00209 #else
00210
00211 bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
00212 {
00213 (void)conn;
00214 (void)sockindex;
00215 return false;
00216 }
00217 #define pre_receive_plain(c,n) do {} WHILE_FALSE
00218 #define get_pre_recved(c,n,b,l) 0
00219 #endif
00220
00221
00222
00223 void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
00224 {
00225 if(data && data->set.verbose) {
00226 va_list ap;
00227 size_t len;
00228 char print_buffer[2048 + 1];
00229 va_start(ap, fmt);
00230 vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
00231 va_end(ap);
00232 len = strlen(print_buffer);
00233 Curl_debug(data, CURLINFO_TEXT, print_buffer, len, NULL);
00234 }
00235 }
00236
00237
00238
00239
00240
00241 void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
00242 {
00243 va_list ap;
00244 size_t len;
00245 va_start(ap, fmt);
00246
00247 vsnprintf(data->state.buffer, BUFSIZE, fmt, ap);
00248
00249 if(data->set.errorbuffer && !data->state.errorbuf) {
00250 snprintf(data->set.errorbuffer, CURL_ERROR_SIZE, "%s", data->state.buffer);
00251 data->state.errorbuf = TRUE;
00252 }
00253 if(data->set.verbose) {
00254 len = strlen(data->state.buffer);
00255 if(len < BUFSIZE - 1) {
00256 data->state.buffer[len] = '\n';
00257 data->state.buffer[++len] = '\0';
00258 }
00259 Curl_debug(data, CURLINFO_TEXT, data->state.buffer, len, NULL);
00260 }
00261
00262 va_end(ap);
00263 }
00264
00265
00266 CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
00267 const char *fmt, ...)
00268 {
00269 struct Curl_easy *data = conn->data;
00270 ssize_t bytes_written;
00271 size_t write_len;
00272 CURLcode result = CURLE_OK;
00273 char *s;
00274 char *sptr;
00275 va_list ap;
00276 va_start(ap, fmt);
00277 s = vaprintf(fmt, ap);
00278 va_end(ap);
00279 if(!s)
00280 return CURLE_OUT_OF_MEMORY;
00281
00282 bytes_written=0;
00283 write_len = strlen(s);
00284 sptr = s;
00285
00286 for(;;) {
00287
00288 result = Curl_write(conn, sockfd, sptr, write_len, &bytes_written);
00289
00290 if(result)
00291 break;
00292
00293 if(data->set.verbose)
00294 Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written, conn);
00295
00296 if((size_t)bytes_written != write_len) {
00297
00298
00299 write_len -= bytes_written;
00300 sptr += bytes_written;
00301 }
00302 else
00303 break;
00304 }
00305
00306 free(s);
00307
00308 return result;
00309 }
00310
00311
00312
00313
00314
00315
00316
00317
00318 CURLcode Curl_write(struct connectdata *conn,
00319 curl_socket_t sockfd,
00320 const void *mem,
00321 size_t len,
00322 ssize_t *written)
00323 {
00324 ssize_t bytes_written;
00325 CURLcode result = CURLE_OK;
00326 int num = (sockfd == conn->sock[SECONDARYSOCKET]);
00327
00328 bytes_written = conn->send[num](conn, num, mem, len, &result);
00329
00330 *written = bytes_written;
00331 if(bytes_written >= 0)
00332
00333 return CURLE_OK;
00334
00335
00336 switch(result) {
00337 case CURLE_AGAIN:
00338 *written = 0;
00339 return CURLE_OK;
00340
00341 case CURLE_OK:
00342
00343 return CURLE_SEND_ERROR;
00344
00345 default:
00346
00347 return result;
00348 }
00349 }
00350
00351 ssize_t Curl_send_plain(struct connectdata *conn, int num,
00352 const void *mem, size_t len, CURLcode *code)
00353 {
00354 curl_socket_t sockfd = conn->sock[num];
00355 ssize_t bytes_written;
00356
00357
00358
00359
00360
00361 pre_receive_plain(conn, num);
00362
00363 #ifdef MSG_FASTOPEN
00364 if(conn->bits.tcp_fastopen) {
00365 bytes_written = sendto(sockfd, mem, len, MSG_FASTOPEN,
00366 conn->ip_addr->ai_addr, conn->ip_addr->ai_addrlen);
00367 conn->bits.tcp_fastopen = FALSE;
00368 }
00369 else
00370 #endif
00371 bytes_written = swrite(sockfd, mem, len);
00372
00373 *code = CURLE_OK;
00374 if(-1 == bytes_written) {
00375 int err = SOCKERRNO;
00376
00377 if(
00378 #ifdef WSAEWOULDBLOCK
00379
00380 (WSAEWOULDBLOCK == err)
00381 #else
00382
00383
00384
00385 (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) ||
00386 (EINPROGRESS == err)
00387 #endif
00388 ) {
00389
00390 bytes_written=0;
00391 *code = CURLE_AGAIN;
00392 }
00393 else {
00394 failf(conn->data, "Send failure: %s",
00395 Curl_strerror(conn, err));
00396 conn->data->state.os_errno = err;
00397 *code = CURLE_SEND_ERROR;
00398 }
00399 }
00400 return bytes_written;
00401 }
00402
00403
00404
00405
00406
00407
00408 CURLcode Curl_write_plain(struct connectdata *conn,
00409 curl_socket_t sockfd,
00410 const void *mem,
00411 size_t len,
00412 ssize_t *written)
00413 {
00414 ssize_t bytes_written;
00415 CURLcode result;
00416 int num = (sockfd == conn->sock[SECONDARYSOCKET]);
00417
00418 bytes_written = Curl_send_plain(conn, num, mem, len, &result);
00419
00420 *written = bytes_written;
00421
00422 return result;
00423 }
00424
00425 ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
00426 size_t len, CURLcode *code)
00427 {
00428 curl_socket_t sockfd = conn->sock[num];
00429 ssize_t nread;
00430
00431
00432 nread = get_pre_recved(conn, num, buf, len);
00433 if(nread > 0) {
00434 *code = CURLE_OK;
00435 return nread;
00436 }
00437
00438 nread = sread(sockfd, buf, len);
00439
00440 *code = CURLE_OK;
00441 if(-1 == nread) {
00442 int err = SOCKERRNO;
00443
00444 if(
00445 #ifdef WSAEWOULDBLOCK
00446
00447 (WSAEWOULDBLOCK == err)
00448 #else
00449
00450
00451
00452 (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
00453 #endif
00454 ) {
00455
00456 *code = CURLE_AGAIN;
00457 }
00458 else {
00459 failf(conn->data, "Recv failure: %s",
00460 Curl_strerror(conn, err));
00461 conn->data->state.os_errno = err;
00462 *code = CURLE_RECV_ERROR;
00463 }
00464 }
00465 return nread;
00466 }
00467
00468 static CURLcode pausewrite(struct Curl_easy *data,
00469 int type,
00470 const char *ptr,
00471 size_t len)
00472 {
00473
00474
00475
00476 struct SingleRequest *k = &data->req;
00477 char *dupl = malloc(len);
00478 if(!dupl)
00479 return CURLE_OUT_OF_MEMORY;
00480
00481 memcpy(dupl, ptr, len);
00482
00483
00484 data->state.tempwrite = dupl;
00485 data->state.tempwritesize = len;
00486 data->state.tempwritetype = type;
00487
00488
00489 k->keepon |= KEEP_RECV_PAUSE;
00490
00491 DEBUGF(infof(data, "Pausing with %zu bytes in buffer for type %02x\n",
00492 len, type));
00493
00494 return CURLE_OK;
00495 }
00496
00497
00498
00499
00500
00501
00502 CURLcode Curl_client_chop_write(struct connectdata *conn,
00503 int type,
00504 char *ptr,
00505 size_t len)
00506 {
00507 struct Curl_easy *data = conn->data;
00508 curl_write_callback writeheader = NULL;
00509 curl_write_callback writebody = NULL;
00510
00511 if(!len)
00512 return CURLE_OK;
00513
00514
00515
00516
00517 if(data->req.keepon & KEEP_RECV_PAUSE) {
00518 size_t newlen;
00519 char *newptr;
00520 if(type != data->state.tempwritetype)
00521
00522 return CURLE_RECV_ERROR;
00523
00524 DEBUGASSERT(data->state.tempwrite);
00525
00526
00527 newlen = len + data->state.tempwritesize;
00528
00529 newptr = realloc(data->state.tempwrite, newlen);
00530 if(!newptr)
00531 return CURLE_OUT_OF_MEMORY;
00532
00533 memcpy(newptr + data->state.tempwritesize, ptr, len);
00534
00535 data->state.tempwrite = newptr;
00536 data->state.tempwritesize = newlen;
00537 return CURLE_OK;
00538 }
00539
00540
00541 if(type & CLIENTWRITE_BODY)
00542 writebody = data->set.fwrite_func;
00543 if((type & CLIENTWRITE_HEADER) &&
00544 (data->set.fwrite_header || data->set.writeheader)) {
00545
00546
00547
00548
00549 writeheader =
00550 data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func;
00551 }
00552
00553
00554 while(len) {
00555 size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE;
00556
00557 if(writebody) {
00558 size_t wrote = writebody(ptr, 1, chunklen, data->set.out);
00559
00560 if(CURL_WRITEFUNC_PAUSE == wrote) {
00561 if(conn->handler->flags & PROTOPT_NONETWORK) {
00562
00563
00564
00565 failf(data, "Write callback asked for PAUSE when not supported!");
00566 return CURLE_WRITE_ERROR;
00567 }
00568 else
00569 return pausewrite(data, type, ptr, len);
00570 }
00571 else if(wrote != chunklen) {
00572 failf(data, "Failed writing body (%zu != %zu)", wrote, chunklen);
00573 return CURLE_WRITE_ERROR;
00574 }
00575 }
00576
00577 if(writeheader) {
00578 size_t wrote = writeheader(ptr, 1, chunklen, data->set.writeheader);
00579
00580 if(CURL_WRITEFUNC_PAUSE == wrote)
00581
00582
00583
00584 return pausewrite(data, CLIENTWRITE_HEADER, ptr, len);
00585
00586 if(wrote != chunklen) {
00587 failf(data, "Failed writing header");
00588 return CURLE_WRITE_ERROR;
00589 }
00590 }
00591
00592 ptr += chunklen;
00593 len -= chunklen;
00594 }
00595
00596 return CURLE_OK;
00597 }
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609 CURLcode Curl_client_write(struct connectdata *conn,
00610 int type,
00611 char *ptr,
00612 size_t len)
00613 {
00614 struct Curl_easy *data = conn->data;
00615
00616 if(0 == len)
00617 len = strlen(ptr);
00618
00619
00620 if((type & CLIENTWRITE_BODY) &&
00621 (conn->handler->protocol & PROTO_FAMILY_FTP) &&
00622 conn->proto.ftpc.transfertype == 'A') {
00623
00624 CURLcode result = Curl_convert_from_network(data, ptr, len);
00625
00626 if(result)
00627 return result;
00628
00629 #ifdef CURL_DO_LINEEND_CONV
00630
00631 len = convert_lineends(data, ptr, len);
00632 #endif
00633 }
00634
00635 return Curl_client_chop_write(conn, type, ptr, len);
00636 }
00637
00638 CURLcode Curl_read_plain(curl_socket_t sockfd,
00639 char *buf,
00640 size_t bytesfromsocket,
00641 ssize_t *n)
00642 {
00643 ssize_t nread = sread(sockfd, buf, bytesfromsocket);
00644
00645 if(-1 == nread) {
00646 int err = SOCKERRNO;
00647 int return_error;
00648 #ifdef USE_WINSOCK
00649 return_error = WSAEWOULDBLOCK == err;
00650 #else
00651 return_error = EWOULDBLOCK == err || EAGAIN == err || EINTR == err;
00652 #endif
00653 if(return_error)
00654 return CURLE_AGAIN;
00655 else
00656 return CURLE_RECV_ERROR;
00657 }
00658
00659
00660 *n = nread;
00661 return CURLE_OK;
00662 }
00663
00664
00665
00666
00667
00668
00669
00670 CURLcode Curl_read(struct connectdata *conn,
00671 curl_socket_t sockfd,
00672 char *buf,
00673 size_t sizerequested,
00674 ssize_t *n)
00675 {
00676 CURLcode result = CURLE_RECV_ERROR;
00677 ssize_t nread = 0;
00678 size_t bytesfromsocket = 0;
00679 char *buffertofill = NULL;
00680
00681
00682 bool pipelining = Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1) &&
00683 (conn->bundle->multiuse == BUNDLE_PIPELINING);
00684
00685
00686
00687
00688 int num = (sockfd == conn->sock[SECONDARYSOCKET]);
00689
00690 *n=0;
00691
00692
00693 if(pipelining) {
00694 size_t bytestocopy = CURLMIN(conn->buf_len - conn->read_pos,
00695 sizerequested);
00696
00697
00698 if(bytestocopy > 0) {
00699 memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy);
00700 conn->read_pos += bytestocopy;
00701 conn->bits.stream_was_rewound = FALSE;
00702
00703 *n = (ssize_t)bytestocopy;
00704 return CURLE_OK;
00705 }
00706
00707
00708 bytesfromsocket = CURLMIN(sizerequested, BUFSIZE * sizeof(char));
00709 buffertofill = conn->master_buffer;
00710 }
00711 else {
00712 bytesfromsocket = CURLMIN((long)sizerequested,
00713 conn->data->set.buffer_size ?
00714 conn->data->set.buffer_size : BUFSIZE);
00715 buffertofill = buf;
00716 }
00717
00718 nread = conn->recv[num](conn, num, buffertofill, bytesfromsocket, &result);
00719 if(nread < 0)
00720 return result;
00721
00722 if(pipelining) {
00723 memcpy(buf, conn->master_buffer, nread);
00724 conn->buf_len = nread;
00725 conn->read_pos = nread;
00726 }
00727
00728 *n += nread;
00729
00730 return CURLE_OK;
00731 }
00732
00733
00734 static int showit(struct Curl_easy *data, curl_infotype type,
00735 char *ptr, size_t size)
00736 {
00737 static const char s_infotype[CURLINFO_END][3] = {
00738 "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
00739
00740 #ifdef CURL_DOES_CONVERSIONS
00741 char buf[BUFSIZE+1];
00742 size_t conv_size = 0;
00743
00744 switch(type) {
00745 case CURLINFO_HEADER_OUT:
00746
00747
00748 if(size > BUFSIZE) {
00749 size = BUFSIZE;
00750 buf[BUFSIZE] = '\0';
00751 }
00752 conv_size = size;
00753 memcpy(buf, ptr, size);
00754
00755
00756
00757
00758 if(size > 4) {
00759 size_t i;
00760 for(i = 0; i < size-4; i++) {
00761 if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) {
00762
00763 conv_size = i + 4;
00764 break;
00765 }
00766 }
00767 }
00768
00769 Curl_convert_from_network(data, buf, conv_size);
00770
00771
00772 ptr = buf;
00773 break;
00774 default:
00775
00776 break;
00777 }
00778 #endif
00779
00780 if(data->set.fdebug)
00781 return (*data->set.fdebug)(data, type, ptr, size,
00782 data->set.debugdata);
00783
00784 switch(type) {
00785 case CURLINFO_TEXT:
00786 case CURLINFO_HEADER_OUT:
00787 case CURLINFO_HEADER_IN:
00788 fwrite(s_infotype[type], 2, 1, data->set.err);
00789 fwrite(ptr, size, 1, data->set.err);
00790 #ifdef CURL_DOES_CONVERSIONS
00791 if(size != conv_size) {
00792
00793 fwrite("\n", 1, 1, data->set.err);
00794 }
00795 #endif
00796 break;
00797 default:
00798 break;
00799 }
00800 return 0;
00801 }
00802
00803 int Curl_debug(struct Curl_easy *data, curl_infotype type,
00804 char *ptr, size_t size,
00805 struct connectdata *conn)
00806 {
00807 int rc;
00808 if(data->set.printhost && conn && conn->host.dispname) {
00809 char buffer[160];
00810 const char *t=NULL;
00811 const char *w="Data";
00812 switch(type) {
00813 case CURLINFO_HEADER_IN:
00814 w = "Header";
00815
00816 case CURLINFO_DATA_IN:
00817 t = "from";
00818 break;
00819 case CURLINFO_HEADER_OUT:
00820 w = "Header";
00821
00822 case CURLINFO_DATA_OUT:
00823 t = "to";
00824 break;
00825 default:
00826 break;
00827 }
00828
00829 if(t) {
00830 snprintf(buffer, sizeof(buffer), "[%s %s %s]", w, t,
00831 conn->host.dispname);
00832 rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer));
00833 if(rc)
00834 return rc;
00835 }
00836 }
00837 rc = showit(data, type, ptr, size);
00838 return rc;
00839 }