diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/easy.c | 70 | ||||
| -rw-r--r-- | lib/sendf.c | 169 | ||||
| -rw-r--r-- | lib/sendf.h | 2 | 
3 files changed, 105 insertions, 136 deletions
| diff --git a/lib/easy.c b/lib/easy.c index b547d1dbe..619312b79 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -1026,73 +1026,15 @@ CURLcode curl_easy_pause(CURL *curl, int action)      /* we have a buffer for sending that we now seem to be able to deliver         since the receive pausing is lifted! */ -    /* get the pointer, type and length in local copies since the function may -       return PAUSE again and then we'll get a new copy allocted and stored in +    /* get the pointer in local copy since the function may return PAUSE +       again and then we'll get a new copy allocted and stored in         the tempwrite variables */      char *tempwrite = data->state.tempwrite; -    char *freewrite = tempwrite; /* store this pointer to free it later */ -    size_t tempsize = data->state.tempwritesize; -    int temptype = data->state.tempwritetype; -    size_t chunklen; - -    /* clear tempwrite here just to make sure it gets cleared if there's no -       further use of it, and make sure we don't clear it after the function -       invoke as it may have been set to a new value by then */ -    data->state.tempwrite = NULL; - -    /* since the write callback API is define to never exceed -       CURL_MAX_WRITE_SIZE bytes in a single call, and since we may in fact -       have more data than that in our buffer here, we must loop sending the -       data in multiple calls until there's no data left or we get another -       pause returned. - -       A tricky part is that the function we call will "buffer" the data -       itself when it pauses on a particular buffer, so we may need to do some -       extra trickery if we get a pause return here. -    */ -    do { -      chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize; - -      result = Curl_client_write(data->easy_conn, -                                 temptype, tempwrite, chunklen); -      if(result) -        /* failures abort the loop at once */ -        break; - -      if(data->state.tempwrite && (tempsize - chunklen)) { -        /* Ouch, the reading is again paused and the block we send is now -           "cached". If this is the final chunk we can leave it like this, but -           if we have more chunks that are cached after this, we need to free -           the newly cached one and put back a version that is truly the entire -           contents that is saved for later -        */ -        char *newptr; - -        /* note that tempsize is still the size as before the callback was -           used, and thus the whole piece of data to keep */ -        newptr = realloc(data->state.tempwrite, tempsize); - -        if(!newptr) { -          free(data->state.tempwrite); /* free old area */ -          data->state.tempwrite = NULL; -          result = CURLE_OUT_OF_MEMORY; -          /* tempwrite will be freed further down */ -          break; -        } -        data->state.tempwrite = newptr; /* store new pointer */ -        memcpy(newptr, tempwrite, tempsize); -        data->state.tempwritesize = tempsize; /* store new size */ -        /* tempwrite will be freed further down */ -        break; /* go back to pausing until further notice */ -      } -      else { -        tempsize -= chunklen;  /* left after the call above */ -        tempwrite += chunklen; /* advance the pointer */ -      } -    } while(!result && tempsize); - -    free(freewrite); /* this is unconditionally no longer used */ +    data->state.tempwrite = NULL; +    result = Curl_client_chop_write(data->easy_conn, data->state.tempwritetype, +                                    tempwrite, data->state.tempwritesize); +    free(tempwrite);    }    /* if there's no error and we're not pausing both directions, we want diff --git a/lib/sendf.c b/lib/sendf.c index 469496c06..2d1a166bd 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -374,25 +374,21 @@ static CURLcode pausewrite(struct SessionHandle *data,  } -/* Curl_client_write() sends data to the write callback(s) - -   The bit pattern defines to what "streams" to write to. Body and/or header. -   The defines are in sendf.h of course. - -   If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the -   local character encoding.  This is a problem and should be changed in -   the future to leave the original data alone. +/* Curl_client_chop_write() writes chunks of data not larger than + * CURL_MAX_WRITE_SIZE via client write callback(s) and + * takes care of pause requests from the callbacks.   */ -CURLcode Curl_client_write(struct connectdata *conn, -                           int type, -                           char *ptr, -                           size_t len) +CURLcode Curl_client_chop_write(struct connectdata *conn, +                                int type, +                                char * ptr, +                                size_t len)  {    struct SessionHandle *data = conn->data; -  size_t wrote; +  curl_write_callback writeheader = NULL; +  curl_write_callback writebody = NULL; -  if(0 == len) -    len = strlen(ptr); +  if(!len) +    return CURLE_OK;    /* If reading is actually paused, we're forced to append this chunk of data       to the already held data, but only if it is the same type as otherwise it @@ -417,78 +413,107 @@ CURLcode Curl_client_write(struct connectdata *conn,      /* update the pointer and the size */      data->state.tempwrite = newptr;      data->state.tempwritesize = newlen; -      return CURLE_OK;    } -  if(type & CLIENTWRITE_BODY) { -    if((conn->handler->protocol&PROTO_FAMILY_FTP) && -       conn->proto.ftpc.transfertype == 'A') { -      /* convert from the network encoding */ -      CURLcode result = Curl_convert_from_network(data, ptr, len); -      /* Curl_convert_from_network calls failf if unsuccessful */ -      if(result) -        return result; +  /* Determine the callback(s) to use. */ +  if(type & CLIENTWRITE_BODY) +    writebody = data->set.fwrite_func; +  if((type & CLIENTWRITE_HEADER) && +     (data->set.fwrite_header || data->set.writeheader)) { +    /* +     * Write headers to the same callback or to the especially setup +     * header callback function (added after version 7.7.1). +     */ +    writeheader = +      data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func; +  } + +  /* Chop data, write chunks. */ +  while(len) { +    size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE; -#ifdef CURL_DO_LINEEND_CONV -      /* convert end-of-line markers */ -      len = convert_lineends(data, ptr, len); -#endif /* CURL_DO_LINEEND_CONV */ -    } -    /* If the previous block of data ended with CR and this block of data is -       just a NL, then the length might be zero */ -    if(len) { -      wrote = data->set.fwrite_func(ptr, 1, len, data->set.out); -    } -    else { -      wrote = len; -    } +    if(writebody) { +      size_t wrote = writebody(ptr, 1, chunklen, data->set.out); -    if(CURL_WRITEFUNC_PAUSE == wrote) { -      if(conn->handler->flags & PROTOPT_NONETWORK) { -        /* Protocols that work without network cannot be paused. This is -           actually only FILE:// just now, and it can't pause since the -           transfer isn't done using the "normal" procedure. */ -        failf(data, "Write callback asked for PAUSE when not supported!"); +      if(CURL_WRITEFUNC_PAUSE == wrote) { +        if(conn->handler->flags & PROTOPT_NONETWORK) { +          /* Protocols that work without network cannot be paused. This is +             actually only FILE:// just now, and it can't pause since the +             transfer isn't done using the "normal" procedure. */ +          failf(data, "Write callback asked for PAUSE when not supported!"); +          return CURLE_WRITE_ERROR; +        } +        else +          return pausewrite(data, type, ptr, len); +      } +      else if(wrote != chunklen) { +        failf(data, "Failed writing body (%zu != %zu)", wrote, chunklen);          return CURLE_WRITE_ERROR;        } -      else -        return pausewrite(data, type, ptr, len); -    } -    else if(wrote != len) { -      failf(data, "Failed writing body (%zu != %zu)", wrote, len); -      return CURLE_WRITE_ERROR;      } -  } -  if((type & CLIENTWRITE_HEADER) && -     (data->set.fwrite_header || data->set.writeheader) ) { -    /* -     * Write headers to the same callback or to the especially setup -     * header callback function (added after version 7.7.1). -     */ -    curl_write_callback writeit= -      data->set.fwrite_header?data->set.fwrite_header:data->set.fwrite_func; - -    /* Note: The header is in the host encoding -       regardless of the ftp transfer mode (ASCII/Image) */ - -    wrote = writeit(ptr, 1, len, data->set.writeheader); -    if(CURL_WRITEFUNC_PAUSE == wrote) -      /* here we pass in the HEADER bit only since if this was body as well -         then it was passed already and clearly that didn't trigger the pause, -         so this is saved for later with the HEADER bit only */ -      return pausewrite(data, CLIENTWRITE_HEADER, ptr, len); - -    if(wrote != len) { -      failf (data, "Failed writing header"); -      return CURLE_WRITE_ERROR; +    if(writeheader) { +      size_t wrote = writeheader(ptr, 1, chunklen, data->set.writeheader); + +      if(CURL_WRITEFUNC_PAUSE == wrote) +        /* here we pass in the HEADER bit only since if this was body as well +           then it was passed already and clearly that didn't trigger the +           pause, so this is saved for later with the HEADER bit only */ +        return pausewrite(data, CLIENTWRITE_HEADER, ptr, len); + +      if(wrote != chunklen) { +        failf (data, "Failed writing header"); +        return CURLE_WRITE_ERROR; +      }      } + +    ptr += chunklen; +    len -= chunklen;    }    return CURLE_OK;  } + +/* Curl_client_write() sends data to the write callback(s) + +   The bit pattern defines to what "streams" to write to. Body and/or header. +   The defines are in sendf.h of course. + +   If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the +   local character encoding.  This is a problem and should be changed in +   the future to leave the original data alone. + */ +CURLcode Curl_client_write(struct connectdata *conn, +                           int type, +                           char *ptr, +                           size_t len) +{ +  struct SessionHandle *data = conn->data; + +  if(0 == len) +    len = strlen(ptr); + +  /* FTP data may need conversion. */ +  if((type & CLIENTWRITE_BODY) && +    (conn->handler->protocol & PROTO_FAMILY_FTP) && +    conn->proto.ftpc.transfertype == 'A') { +    /* convert from the network encoding */ +    CURLcode result = Curl_convert_from_network(data, ptr, len); +    /* Curl_convert_from_network calls failf if unsuccessful */ +    if(result) +      return result; + +#ifdef CURL_DO_LINEEND_CONV +    /* convert end-of-line markers */ +    len = convert_lineends(data, ptr, len); +#endif /* CURL_DO_LINEEND_CONV */ +    } + +  return Curl_client_chop_write(conn, type, ptr, len); +} +  CURLcode Curl_read_plain(curl_socket_t sockfd,                           char *buf,                           size_t bytesfromsocket, diff --git a/lib/sendf.h b/lib/sendf.h index 23c720661..86f06cf9b 100644 --- a/lib/sendf.h +++ b/lib/sendf.h @@ -51,6 +51,8 @@ void Curl_failf(struct SessionHandle *, const char *fmt, ...);  #define CLIENTWRITE_HEADER (1<<1)  #define CLIENTWRITE_BOTH   (CLIENTWRITE_BODY|CLIENTWRITE_HEADER) +CURLcode Curl_client_chop_write(struct connectdata *conn, int type, char *ptr, +                                size_t len) WARN_UNUSED_RESULT;  CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr,                             size_t len) WARN_UNUSED_RESULT; | 
