Annotation of embedaddon/curl/lib/sendf.c, revision 1.1.1.1

1.1       misho       1: /***************************************************************************
                      2:  *                                  _   _ ____  _
                      3:  *  Project                     ___| | | |  _ \| |
                      4:  *                             / __| | | | |_) | |
                      5:  *                            | (__| |_| |  _ <| |___
                      6:  *                             \___|\___/|_| \_\_____|
                      7:  *
                      8:  * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
                      9:  *
                     10:  * This software is licensed as described in the file COPYING, which
                     11:  * you should have received as part of this distribution. The terms
                     12:  * are also available at https://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:  ***************************************************************************/
                     22: 
                     23: #include "curl_setup.h"
                     24: 
                     25: #ifdef HAVE_NETINET_IN_H
                     26: #include <netinet/in.h>
                     27: #endif
                     28: 
                     29: #ifdef HAVE_LINUX_TCP_H
                     30: #include <linux/tcp.h>
                     31: #endif
                     32: 
                     33: #include <curl/curl.h>
                     34: 
                     35: #include "urldata.h"
                     36: #include "sendf.h"
                     37: #include "connect.h"
                     38: #include "vtls/vtls.h"
                     39: #include "vssh/ssh.h"
                     40: #include "easyif.h"
                     41: #include "multiif.h"
                     42: #include "non-ascii.h"
                     43: #include "strerror.h"
                     44: #include "select.h"
                     45: #include "strdup.h"
                     46: #include "http2.h"
                     47: 
                     48: /* The last 3 #include files should be in this order */
                     49: #include "curl_printf.h"
                     50: #include "curl_memory.h"
                     51: #include "memdebug.h"
                     52: 
                     53: #ifdef CURL_DO_LINEEND_CONV
                     54: /*
                     55:  * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
                     56:  * (\n), with special processing for CRLF sequences that are split between two
                     57:  * blocks of data.  Remaining, bare CRs are changed to LFs.  The possibly new
                     58:  * size of the data is returned.
                     59:  */
                     60: static size_t convert_lineends(struct Curl_easy *data,
                     61:                                char *startPtr, size_t size)
                     62: {
                     63:   char *inPtr, *outPtr;
                     64: 
                     65:   /* sanity check */
                     66:   if((startPtr == NULL) || (size < 1)) {
                     67:     return size;
                     68:   }
                     69: 
                     70:   if(data->state.prev_block_had_trailing_cr) {
                     71:     /* The previous block of incoming data
                     72:        had a trailing CR, which was turned into a LF. */
                     73:     if(*startPtr == '\n') {
                     74:       /* This block of incoming data starts with the
                     75:          previous block's LF so get rid of it */
                     76:       memmove(startPtr, startPtr + 1, size-1);
                     77:       size--;
                     78:       /* and it wasn't a bare CR but a CRLF conversion instead */
                     79:       data->state.crlf_conversions++;
                     80:     }
                     81:     data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */
                     82:   }
                     83: 
                     84:   /* find 1st CR, if any */
                     85:   inPtr = outPtr = memchr(startPtr, '\r', size);
                     86:   if(inPtr) {
                     87:     /* at least one CR, now look for CRLF */
                     88:     while(inPtr < (startPtr + size-1)) {
                     89:       /* note that it's size-1, so we'll never look past the last byte */
                     90:       if(memcmp(inPtr, "\r\n", 2) == 0) {
                     91:         /* CRLF found, bump past the CR and copy the NL */
                     92:         inPtr++;
                     93:         *outPtr = *inPtr;
                     94:         /* keep track of how many CRLFs we converted */
                     95:         data->state.crlf_conversions++;
                     96:       }
                     97:       else {
                     98:         if(*inPtr == '\r') {
                     99:           /* lone CR, move LF instead */
                    100:           *outPtr = '\n';
                    101:         }
                    102:         else {
                    103:           /* not a CRLF nor a CR, just copy whatever it is */
                    104:           *outPtr = *inPtr;
                    105:         }
                    106:       }
                    107:       outPtr++;
                    108:       inPtr++;
                    109:     } /* end of while loop */
                    110: 
                    111:     if(inPtr < startPtr + size) {
                    112:       /* handle last byte */
                    113:       if(*inPtr == '\r') {
                    114:         /* deal with a CR at the end of the buffer */
                    115:         *outPtr = '\n'; /* copy a NL instead */
                    116:         /* note that a CRLF might be split across two blocks */
                    117:         data->state.prev_block_had_trailing_cr = TRUE;
                    118:       }
                    119:       else {
                    120:         /* copy last byte */
                    121:         *outPtr = *inPtr;
                    122:       }
                    123:       outPtr++;
                    124:     }
                    125:     if(outPtr < startPtr + size)
                    126:       /* tidy up by null terminating the now shorter data */
                    127:       *outPtr = '\0';
                    128: 
                    129:     return (outPtr - startPtr);
                    130:   }
                    131:   return size;
                    132: }
                    133: #endif /* CURL_DO_LINEEND_CONV */
                    134: 
                    135: #ifdef USE_RECV_BEFORE_SEND_WORKAROUND
                    136: bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
                    137: {
                    138:   struct postponed_data * const psnd = &(conn->postponed[sockindex]);
                    139:   return psnd->buffer && psnd->allocated_size &&
                    140:          psnd->recv_size > psnd->recv_processed;
                    141: }
                    142: 
                    143: static void pre_receive_plain(struct connectdata *conn, int num)
                    144: {
                    145:   const curl_socket_t sockfd = conn->sock[num];
                    146:   struct postponed_data * const psnd = &(conn->postponed[num]);
                    147:   size_t bytestorecv = psnd->allocated_size - psnd->recv_size;
                    148:   /* WinSock will destroy unread received data if send() is
                    149:      failed.
                    150:      To avoid lossage of received data, recv() must be
                    151:      performed before every send() if any incoming data is
                    152:      available. However, skip this, if buffer is already full. */
                    153:   if((conn->handler->protocol&PROTO_FAMILY_HTTP) != 0 &&
                    154:      conn->recv[num] == Curl_recv_plain &&
                    155:      (!psnd->buffer || bytestorecv)) {
                    156:     const int readymask = Curl_socket_check(sockfd, CURL_SOCKET_BAD,
                    157:                                             CURL_SOCKET_BAD, 0);
                    158:     if(readymask != -1 && (readymask & CURL_CSELECT_IN) != 0) {
                    159:       /* Have some incoming data */
                    160:       if(!psnd->buffer) {
                    161:         /* Use buffer double default size for intermediate buffer */
                    162:         psnd->allocated_size = 2 * conn->data->set.buffer_size;
                    163:         psnd->buffer = malloc(psnd->allocated_size);
                    164:         psnd->recv_size = 0;
                    165:         psnd->recv_processed = 0;
                    166: #ifdef DEBUGBUILD
                    167:         psnd->bindsock = sockfd; /* Used only for DEBUGASSERT */
                    168: #endif /* DEBUGBUILD */
                    169:         bytestorecv = psnd->allocated_size;
                    170:       }
                    171:       if(psnd->buffer) {
                    172:         ssize_t recvedbytes;
                    173:         DEBUGASSERT(psnd->bindsock == sockfd);
                    174:         recvedbytes = sread(sockfd, psnd->buffer + psnd->recv_size,
                    175:                             bytestorecv);
                    176:         if(recvedbytes > 0)
                    177:           psnd->recv_size += recvedbytes;
                    178:       }
                    179:       else
                    180:         psnd->allocated_size = 0;
                    181:     }
                    182:   }
                    183: }
                    184: 
                    185: static ssize_t get_pre_recved(struct connectdata *conn, int num, char *buf,
                    186:                               size_t len)
                    187: {
                    188:   struct postponed_data * const psnd = &(conn->postponed[num]);
                    189:   size_t copysize;
                    190:   if(!psnd->buffer)
                    191:     return 0;
                    192: 
                    193:   DEBUGASSERT(psnd->allocated_size > 0);
                    194:   DEBUGASSERT(psnd->recv_size <= psnd->allocated_size);
                    195:   DEBUGASSERT(psnd->recv_processed <= psnd->recv_size);
                    196:   /* Check and process data that already received and storied in internal
                    197:      intermediate buffer */
                    198:   if(psnd->recv_size > psnd->recv_processed) {
                    199:     DEBUGASSERT(psnd->bindsock == conn->sock[num]);
                    200:     copysize = CURLMIN(len, psnd->recv_size - psnd->recv_processed);
                    201:     memcpy(buf, psnd->buffer + psnd->recv_processed, copysize);
                    202:     psnd->recv_processed += copysize;
                    203:   }
                    204:   else
                    205:     copysize = 0; /* buffer was allocated, but nothing was received */
                    206: 
                    207:   /* Free intermediate buffer if it has no unprocessed data */
                    208:   if(psnd->recv_processed == psnd->recv_size) {
                    209:     free(psnd->buffer);
                    210:     psnd->buffer = NULL;
                    211:     psnd->allocated_size = 0;
                    212:     psnd->recv_size = 0;
                    213:     psnd->recv_processed = 0;
                    214: #ifdef DEBUGBUILD
                    215:     psnd->bindsock = CURL_SOCKET_BAD;
                    216: #endif /* DEBUGBUILD */
                    217:   }
                    218:   return (ssize_t)copysize;
                    219: }
                    220: #else  /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
                    221: /* Use "do-nothing" macros instead of functions when workaround not used */
                    222: bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
                    223: {
                    224:   (void)conn;
                    225:   (void)sockindex;
                    226:   return false;
                    227: }
                    228: #define pre_receive_plain(c,n) do {} while(0)
                    229: #define get_pre_recved(c,n,b,l) 0
                    230: #endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
                    231: 
                    232: /* Curl_infof() is for info message along the way */
                    233: 
                    234: void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
                    235: {
                    236:   if(data && data->set.verbose) {
                    237:     va_list ap;
                    238:     size_t len;
                    239:     char print_buffer[2048 + 1];
                    240:     va_start(ap, fmt);
                    241:     len = mvsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
                    242:     /*
                    243:      * Indicate truncation of the input by replacing the last 3 characters
                    244:      * with "...", and transfer the newline over in case the format had one.
                    245:      */
                    246:     if(len >= sizeof(print_buffer)) {
                    247:       len = strlen(fmt);
                    248:       if(fmt[--len] == '\n')
                    249:         msnprintf(print_buffer + (sizeof(print_buffer) - 5), 5, "...\n");
                    250:       else
                    251:         msnprintf(print_buffer + (sizeof(print_buffer) - 4), 4, "...");
                    252:     }
                    253:     va_end(ap);
                    254:     len = strlen(print_buffer);
                    255:     Curl_debug(data, CURLINFO_TEXT, print_buffer, len);
                    256:   }
                    257: }
                    258: 
                    259: /* Curl_failf() is for messages stating why we failed.
                    260:  * The message SHALL NOT include any LF or CR.
                    261:  */
                    262: 
                    263: void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
                    264: {
                    265:   if(data->set.verbose || data->set.errorbuffer) {
                    266:     va_list ap;
                    267:     size_t len;
                    268:     char error[CURL_ERROR_SIZE + 2];
                    269:     va_start(ap, fmt);
                    270:     mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
                    271:     len = strlen(error);
                    272: 
                    273:     if(data->set.errorbuffer && !data->state.errorbuf) {
                    274:       strcpy(data->set.errorbuffer, error);
                    275:       data->state.errorbuf = TRUE; /* wrote error string */
                    276:     }
                    277:     if(data->set.verbose) {
                    278:       error[len] = '\n';
                    279:       error[++len] = '\0';
                    280:       Curl_debug(data, CURLINFO_TEXT, error, len);
                    281:     }
                    282:     va_end(ap);
                    283:   }
                    284: }
                    285: 
                    286: /* Curl_sendf() sends formatted data to the server */
                    287: CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
                    288:                     const char *fmt, ...)
                    289: {
                    290:   struct Curl_easy *data = conn->data;
                    291:   ssize_t bytes_written;
                    292:   size_t write_len;
                    293:   CURLcode result = CURLE_OK;
                    294:   char *s;
                    295:   char *sptr;
                    296:   va_list ap;
                    297:   va_start(ap, fmt);
                    298:   s = vaprintf(fmt, ap); /* returns an allocated string */
                    299:   va_end(ap);
                    300:   if(!s)
                    301:     return CURLE_OUT_OF_MEMORY; /* failure */
                    302: 
                    303:   bytes_written = 0;
                    304:   write_len = strlen(s);
                    305:   sptr = s;
                    306: 
                    307:   for(;;) {
                    308:     /* Write the buffer to the socket */
                    309:     result = Curl_write(conn, sockfd, sptr, write_len, &bytes_written);
                    310: 
                    311:     if(result)
                    312:       break;
                    313: 
                    314:     if(data->set.verbose)
                    315:       Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written);
                    316: 
                    317:     if((size_t)bytes_written != write_len) {
                    318:       /* if not all was written at once, we must advance the pointer, decrease
                    319:          the size left and try again! */
                    320:       write_len -= bytes_written;
                    321:       sptr += bytes_written;
                    322:     }
                    323:     else
                    324:       break;
                    325:   }
                    326: 
                    327:   free(s); /* free the output string */
                    328: 
                    329:   return result;
                    330: }
                    331: 
                    332: /*
                    333:  * Curl_write() is an internal write function that sends data to the
                    334:  * server. Works with plain sockets, SCP, SSL or kerberos.
                    335:  *
                    336:  * If the write would block (CURLE_AGAIN), we return CURLE_OK and
                    337:  * (*written == 0). Otherwise we return regular CURLcode value.
                    338:  */
                    339: CURLcode Curl_write(struct connectdata *conn,
                    340:                     curl_socket_t sockfd,
                    341:                     const void *mem,
                    342:                     size_t len,
                    343:                     ssize_t *written)
                    344: {
                    345:   ssize_t bytes_written;
                    346:   CURLcode result = CURLE_OK;
                    347:   int num = (sockfd == conn->sock[SECONDARYSOCKET]);
                    348: 
                    349:   bytes_written = conn->send[num](conn, num, mem, len, &result);
                    350: 
                    351:   *written = bytes_written;
                    352:   if(bytes_written >= 0)
                    353:     /* we completely ignore the curlcode value when subzero is not returned */
                    354:     return CURLE_OK;
                    355: 
                    356:   /* handle CURLE_AGAIN or a send failure */
                    357:   switch(result) {
                    358:   case CURLE_AGAIN:
                    359:     *written = 0;
                    360:     return CURLE_OK;
                    361: 
                    362:   case CURLE_OK:
                    363:     /* general send failure */
                    364:     return CURLE_SEND_ERROR;
                    365: 
                    366:   default:
                    367:     /* we got a specific curlcode, forward it */
                    368:     return result;
                    369:   }
                    370: }
                    371: 
                    372: ssize_t Curl_send_plain(struct connectdata *conn, int num,
                    373:                         const void *mem, size_t len, CURLcode *code)
                    374: {
                    375:   curl_socket_t sockfd = conn->sock[num];
                    376:   ssize_t bytes_written;
                    377:   /* WinSock will destroy unread received data if send() is
                    378:      failed.
                    379:      To avoid lossage of received data, recv() must be
                    380:      performed before every send() if any incoming data is
                    381:      available. */
                    382:   pre_receive_plain(conn, num);
                    383: 
                    384: #if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
                    385:   if(conn->bits.tcp_fastopen) {
                    386:     bytes_written = sendto(sockfd, mem, len, MSG_FASTOPEN,
                    387:                            conn->ip_addr->ai_addr, conn->ip_addr->ai_addrlen);
                    388:     conn->bits.tcp_fastopen = FALSE;
                    389:   }
                    390:   else
                    391: #endif
                    392:     bytes_written = swrite(sockfd, mem, len);
                    393: 
                    394:   *code = CURLE_OK;
                    395:   if(-1 == bytes_written) {
                    396:     int err = SOCKERRNO;
                    397: 
                    398:     if(
                    399: #ifdef WSAEWOULDBLOCK
                    400:       /* This is how Windows does it */
                    401:       (WSAEWOULDBLOCK == err)
                    402: #else
                    403:       /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
                    404:          due to its inability to send off data without blocking. We therefore
                    405:          treat both error codes the same here */
                    406:       (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) ||
                    407:       (EINPROGRESS == err)
                    408: #endif
                    409:       ) {
                    410:       /* this is just a case of EWOULDBLOCK */
                    411:       bytes_written = 0;
                    412:       *code = CURLE_AGAIN;
                    413:     }
                    414:     else {
                    415:       char buffer[STRERROR_LEN];
                    416:       failf(conn->data, "Send failure: %s",
                    417:             Curl_strerror(err, buffer, sizeof(buffer)));
                    418:       conn->data->state.os_errno = err;
                    419:       *code = CURLE_SEND_ERROR;
                    420:     }
                    421:   }
                    422:   return bytes_written;
                    423: }
                    424: 
                    425: /*
                    426:  * Curl_write_plain() is an internal write function that sends data to the
                    427:  * server using plain sockets only. Otherwise meant to have the exact same
                    428:  * proto as Curl_write()
                    429:  */
                    430: CURLcode Curl_write_plain(struct connectdata *conn,
                    431:                           curl_socket_t sockfd,
                    432:                           const void *mem,
                    433:                           size_t len,
                    434:                           ssize_t *written)
                    435: {
                    436:   ssize_t bytes_written;
                    437:   CURLcode result;
                    438:   int num = (sockfd == conn->sock[SECONDARYSOCKET]);
                    439: 
                    440:   bytes_written = Curl_send_plain(conn, num, mem, len, &result);
                    441: 
                    442:   *written = bytes_written;
                    443: 
                    444:   return result;
                    445: }
                    446: 
                    447: ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
                    448:                         size_t len, CURLcode *code)
                    449: {
                    450:   curl_socket_t sockfd = conn->sock[num];
                    451:   ssize_t nread;
                    452:   /* Check and return data that already received and storied in internal
                    453:      intermediate buffer */
                    454:   nread = get_pre_recved(conn, num, buf, len);
                    455:   if(nread > 0) {
                    456:     *code = CURLE_OK;
                    457:     return nread;
                    458:   }
                    459: 
                    460:   nread = sread(sockfd, buf, len);
                    461: 
                    462:   *code = CURLE_OK;
                    463:   if(-1 == nread) {
                    464:     int err = SOCKERRNO;
                    465: 
                    466:     if(
                    467: #ifdef WSAEWOULDBLOCK
                    468:       /* This is how Windows does it */
                    469:       (WSAEWOULDBLOCK == err)
                    470: #else
                    471:       /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
                    472:          due to its inability to send off data without blocking. We therefore
                    473:          treat both error codes the same here */
                    474:       (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
                    475: #endif
                    476:       ) {
                    477:       /* this is just a case of EWOULDBLOCK */
                    478:       *code = CURLE_AGAIN;
                    479:     }
                    480:     else {
                    481:       char buffer[STRERROR_LEN];
                    482:       failf(conn->data, "Recv failure: %s",
                    483:             Curl_strerror(err, buffer, sizeof(buffer)));
                    484:       conn->data->state.os_errno = err;
                    485:       *code = CURLE_RECV_ERROR;
                    486:     }
                    487:   }
                    488:   return nread;
                    489: }
                    490: 
                    491: static CURLcode pausewrite(struct Curl_easy *data,
                    492:                            int type, /* what type of data */
                    493:                            const char *ptr,
                    494:                            size_t len)
                    495: {
                    496:   /* signalled to pause sending on this connection, but since we have data
                    497:      we want to send we need to dup it to save a copy for when the sending
                    498:      is again enabled */
                    499:   struct SingleRequest *k = &data->req;
                    500:   struct UrlState *s = &data->state;
                    501:   char *dupl;
                    502:   unsigned int i;
                    503:   bool newtype = TRUE;
                    504: 
                    505:   /* If this transfers over HTTP/2, pause the stream! */
                    506:   Curl_http2_stream_pause(data, TRUE);
                    507: 
                    508:   if(s->tempcount) {
                    509:     for(i = 0; i< s->tempcount; i++) {
                    510:       if(s->tempwrite[i].type == type) {
                    511:         /* data for this type exists */
                    512:         newtype = FALSE;
                    513:         break;
                    514:       }
                    515:     }
                    516:     DEBUGASSERT(i < 3);
                    517:   }
                    518:   else
                    519:     i = 0;
                    520: 
                    521:   if(!newtype) {
                    522:     /* append new data to old data */
                    523: 
                    524:     /* figure out the new size of the data to save */
                    525:     size_t newlen = len + s->tempwrite[i].len;
                    526:     /* allocate the new memory area */
                    527:     char *newptr = realloc(s->tempwrite[i].buf, newlen);
                    528:     if(!newptr)
                    529:       return CURLE_OUT_OF_MEMORY;
                    530:     /* copy the new data to the end of the new area */
                    531:     memcpy(newptr + s->tempwrite[i].len, ptr, len);
                    532: 
                    533:     /* update the pointer and the size */
                    534:     s->tempwrite[i].buf = newptr;
                    535:     s->tempwrite[i].len = newlen;
                    536: 
                    537:     len = newlen; /* for the debug output below */
                    538:   }
                    539:   else {
                    540:     dupl = Curl_memdup(ptr, len);
                    541:     if(!dupl)
                    542:       return CURLE_OUT_OF_MEMORY;
                    543: 
                    544:     /* store this information in the state struct for later use */
                    545:     s->tempwrite[i].buf = dupl;
                    546:     s->tempwrite[i].len = len;
                    547:     s->tempwrite[i].type = type;
                    548: 
                    549:     if(newtype)
                    550:       s->tempcount++;
                    551:   }
                    552: 
                    553:   /* mark the connection as RECV paused */
                    554:   k->keepon |= KEEP_RECV_PAUSE;
                    555: 
                    556:   DEBUGF(infof(data, "Paused %zu bytes in buffer for type %02x\n",
                    557:                len, type));
                    558: 
                    559:   return CURLE_OK;
                    560: }
                    561: 
                    562: 
                    563: /* chop_write() writes chunks of data not larger than CURL_MAX_WRITE_SIZE via
                    564:  * client write callback(s) and takes care of pause requests from the
                    565:  * callbacks.
                    566:  */
                    567: static CURLcode chop_write(struct connectdata *conn,
                    568:                            int type,
                    569:                            char *optr,
                    570:                            size_t olen)
                    571: {
                    572:   struct Curl_easy *data = conn->data;
                    573:   curl_write_callback writeheader = NULL;
                    574:   curl_write_callback writebody = NULL;
                    575:   char *ptr = optr;
                    576:   size_t len = olen;
                    577: 
                    578:   if(!len)
                    579:     return CURLE_OK;
                    580: 
                    581:   /* If reading is paused, append this data to the already held data for this
                    582:      type. */
                    583:   if(data->req.keepon & KEEP_RECV_PAUSE)
                    584:     return pausewrite(data, type, ptr, len);
                    585: 
                    586:   /* Determine the callback(s) to use. */
                    587:   if(type & CLIENTWRITE_BODY)
                    588:     writebody = data->set.fwrite_func;
                    589:   if((type & CLIENTWRITE_HEADER) &&
                    590:      (data->set.fwrite_header || data->set.writeheader)) {
                    591:     /*
                    592:      * Write headers to the same callback or to the especially setup
                    593:      * header callback function (added after version 7.7.1).
                    594:      */
                    595:     writeheader =
                    596:       data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func;
                    597:   }
                    598: 
                    599:   /* Chop data, write chunks. */
                    600:   while(len) {
                    601:     size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE;
                    602: 
                    603:     if(writebody) {
                    604:       size_t wrote;
                    605:       Curl_set_in_callback(data, true);
                    606:       wrote = writebody(ptr, 1, chunklen, data->set.out);
                    607:       Curl_set_in_callback(data, false);
                    608: 
                    609:       if(CURL_WRITEFUNC_PAUSE == wrote) {
                    610:         if(conn->handler->flags & PROTOPT_NONETWORK) {
                    611:           /* Protocols that work without network cannot be paused. This is
                    612:              actually only FILE:// just now, and it can't pause since the
                    613:              transfer isn't done using the "normal" procedure. */
                    614:           failf(data, "Write callback asked for PAUSE when not supported!");
                    615:           return CURLE_WRITE_ERROR;
                    616:         }
                    617:         return pausewrite(data, type, ptr, len);
                    618:       }
                    619:       if(wrote != chunklen) {
                    620:         failf(data, "Failed writing body (%zu != %zu)", wrote, chunklen);
                    621:         return CURLE_WRITE_ERROR;
                    622:       }
                    623:     }
                    624: 
                    625:     ptr += chunklen;
                    626:     len -= chunklen;
                    627:   }
                    628: 
                    629:   if(writeheader) {
                    630:     size_t wrote;
                    631:     ptr = optr;
                    632:     len = olen;
                    633:     Curl_set_in_callback(data, true);
                    634:     wrote = writeheader(ptr, 1, len, data->set.writeheader);
                    635:     Curl_set_in_callback(data, false);
                    636: 
                    637:     if(CURL_WRITEFUNC_PAUSE == wrote)
                    638:       /* here we pass in the HEADER bit only since if this was body as well
                    639:          then it was passed already and clearly that didn't trigger the
                    640:          pause, so this is saved for later with the HEADER bit only */
                    641:       return pausewrite(data, CLIENTWRITE_HEADER, ptr, len);
                    642: 
                    643:     if(wrote != len) {
                    644:       failf(data, "Failed writing header");
                    645:       return CURLE_WRITE_ERROR;
                    646:     }
                    647:   }
                    648: 
                    649:   return CURLE_OK;
                    650: }
                    651: 
                    652: 
                    653: /* Curl_client_write() sends data to the write callback(s)
                    654: 
                    655:    The bit pattern defines to what "streams" to write to. Body and/or header.
                    656:    The defines are in sendf.h of course.
                    657: 
                    658:    If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
                    659:    local character encoding.  This is a problem and should be changed in
                    660:    the future to leave the original data alone.
                    661:  */
                    662: CURLcode Curl_client_write(struct connectdata *conn,
                    663:                            int type,
                    664:                            char *ptr,
                    665:                            size_t len)
                    666: {
                    667:   struct Curl_easy *data = conn->data;
                    668: 
                    669:   if(0 == len)
                    670:     len = strlen(ptr);
                    671: 
                    672:   DEBUGASSERT(type <= 3);
                    673: 
                    674:   /* FTP data may need conversion. */
                    675:   if((type & CLIENTWRITE_BODY) &&
                    676:     (conn->handler->protocol & PROTO_FAMILY_FTP) &&
                    677:     conn->proto.ftpc.transfertype == 'A') {
                    678:     /* convert from the network encoding */
                    679:     CURLcode result = Curl_convert_from_network(data, ptr, len);
                    680:     /* Curl_convert_from_network calls failf if unsuccessful */
                    681:     if(result)
                    682:       return result;
                    683: 
                    684: #ifdef CURL_DO_LINEEND_CONV
                    685:     /* convert end-of-line markers */
                    686:     len = convert_lineends(data, ptr, len);
                    687: #endif /* CURL_DO_LINEEND_CONV */
                    688:     }
                    689: 
                    690:   return chop_write(conn, type, ptr, len);
                    691: }
                    692: 
                    693: CURLcode Curl_read_plain(curl_socket_t sockfd,
                    694:                          char *buf,
                    695:                          size_t bytesfromsocket,
                    696:                          ssize_t *n)
                    697: {
                    698:   ssize_t nread = sread(sockfd, buf, bytesfromsocket);
                    699: 
                    700:   if(-1 == nread) {
                    701:     const int err = SOCKERRNO;
                    702:     const bool return_error =
                    703: #ifdef USE_WINSOCK
                    704:       WSAEWOULDBLOCK == err
                    705: #else
                    706:       EWOULDBLOCK == err || EAGAIN == err || EINTR == err
                    707: #endif
                    708:       ;
                    709:     *n = 0; /* no data returned */
                    710:     if(return_error)
                    711:       return CURLE_AGAIN;
                    712:     return CURLE_RECV_ERROR;
                    713:   }
                    714: 
                    715:   *n = nread;
                    716:   return CURLE_OK;
                    717: }
                    718: 
                    719: /*
                    720:  * Internal read-from-socket function. This is meant to deal with plain
                    721:  * sockets, SSL sockets and kerberos sockets.
                    722:  *
                    723:  * Returns a regular CURLcode value.
                    724:  */
                    725: CURLcode Curl_read(struct connectdata *conn, /* connection data */
                    726:                    curl_socket_t sockfd,     /* read from this socket */
                    727:                    char *buf,                /* store read data here */
                    728:                    size_t sizerequested,     /* max amount to read */
                    729:                    ssize_t *n)               /* amount bytes read */
                    730: {
                    731:   CURLcode result = CURLE_RECV_ERROR;
                    732:   ssize_t nread = 0;
                    733:   size_t bytesfromsocket = 0;
                    734:   char *buffertofill = NULL;
                    735:   struct Curl_easy *data = conn->data;
                    736: 
                    737:   /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
                    738:      If it is the second socket, we set num to 1. Otherwise to 0. This lets
                    739:      us use the correct ssl handle. */
                    740:   int num = (sockfd == conn->sock[SECONDARYSOCKET]);
                    741: 
                    742:   *n = 0; /* reset amount to zero */
                    743: 
                    744:   bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
                    745:   buffertofill = buf;
                    746: 
                    747:   nread = conn->recv[num](conn, num, buffertofill, bytesfromsocket, &result);
                    748:   if(nread < 0)
                    749:     return result;
                    750: 
                    751:   *n += nread;
                    752: 
                    753:   return CURLE_OK;
                    754: }
                    755: 
                    756: /* return 0 on success */
                    757: int Curl_debug(struct Curl_easy *data, curl_infotype type,
                    758:                char *ptr, size_t size)
                    759: {
                    760:   static const char s_infotype[CURLINFO_END][3] = {
                    761:     "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
                    762:   int rc = 0;
                    763: 
                    764: #ifdef CURL_DOES_CONVERSIONS
                    765:   char *buf = NULL;
                    766:   size_t conv_size = 0;
                    767: 
                    768:   switch(type) {
                    769:   case CURLINFO_HEADER_OUT:
                    770:     buf = Curl_memdup(ptr, size);
                    771:     if(!buf)
                    772:       return 1;
                    773:     conv_size = size;
                    774: 
                    775:     /* Special processing is needed for this block if it
                    776:      * contains both headers and data (separated by CRLFCRLF).
                    777:      * We want to convert just the headers, leaving the data as-is.
                    778:      */
                    779:     if(size > 4) {
                    780:       size_t i;
                    781:       for(i = 0; i < size-4; i++) {
                    782:         if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) {
                    783:           /* convert everything through this CRLFCRLF but no further */
                    784:           conv_size = i + 4;
                    785:           break;
                    786:         }
                    787:       }
                    788:     }
                    789: 
                    790:     Curl_convert_from_network(data, buf, conv_size);
                    791:     /* Curl_convert_from_network calls failf if unsuccessful */
                    792:     /* we might as well continue even if it fails...   */
                    793:     ptr = buf; /* switch pointer to use my buffer instead */
                    794:     break;
                    795:   default:
                    796:     /* leave everything else as-is */
                    797:     break;
                    798:   }
                    799: #endif /* CURL_DOES_CONVERSIONS */
                    800: 
                    801:   if(data->set.fdebug) {
                    802:     Curl_set_in_callback(data, true);
                    803:     rc = (*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
                    804:     Curl_set_in_callback(data, false);
                    805:   }
                    806:   else {
                    807:     switch(type) {
                    808:     case CURLINFO_TEXT:
                    809:     case CURLINFO_HEADER_OUT:
                    810:     case CURLINFO_HEADER_IN:
                    811:       fwrite(s_infotype[type], 2, 1, data->set.err);
                    812:       fwrite(ptr, size, 1, data->set.err);
                    813: #ifdef CURL_DOES_CONVERSIONS
                    814:       if(size != conv_size) {
                    815:         /* we had untranslated data so we need an explicit newline */
                    816:         fwrite("\n", 1, 1, data->set.err);
                    817:       }
                    818: #endif
                    819:       break;
                    820:     default: /* nada */
                    821:       break;
                    822:     }
                    823:   }
                    824: #ifdef CURL_DOES_CONVERSIONS
                    825:   free(buf);
                    826: #endif
                    827:   return rc;
                    828: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>