~ubuntu-branches/ubuntu/quantal/curl/quantal

« back to all changes in this revision

Viewing changes to lib/http_chunks.c

  • Committer: Bazaar Package Importer
  • Author(s): Domenico Andreoli
  • Date: 2002-03-12 19:06:21 UTC
  • Revision ID: james.westby@ubuntu.com-20020312190621-iqx7k9cipo5d0ifr
Tags: upstream-7.9.5
ImportĀ upstreamĀ versionĀ 7.9.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 *                                  _   _ ____  _     
 
3
 *  Project                     ___| | | |  _ \| |    
 
4
 *                             / __| | | | |_) | |    
 
5
 *                            | (__| |_| |  _ <| |___ 
 
6
 *                             \___|\___/|_| \_\_____|
 
7
 *
 
8
 * Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al.
 
9
 *
 
10
 * In order to be useful for every potential user, curl and libcurl are
 
11
 * dual-licensed under the MPL and the MIT/X-derivate licenses.
 
12
 *
 
13
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 
14
 * copies of the Software, and permit persons to whom the Software is
 
15
 * furnished to do so, under the terms of the MPL or the MIT/X-derivate
 
16
 * licenses. You may pick one of these licenses.
 
17
 *
 
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 
19
 * KIND, either express or implied.
 
20
 *
 
21
 * $Id: http_chunks.c,v 1.9 2001/10/11 09:32:19 bumblebury Exp $
 
22
 *****************************************************************************/
 
23
#include "setup.h"
 
24
 
 
25
/* -- WIN32 approved -- */
 
26
#include <stdio.h>
 
27
#include <string.h>
 
28
#include <stdarg.h>
 
29
#include <stdlib.h>
 
30
#include <ctype.h>
 
31
 
 
32
#include "urldata.h" /* it includes http_chunks.h */
 
33
#include "sendf.h"   /* for the client write stuff */
 
34
 
 
35
#define _MPRINTF_REPLACE /* use our functions only */
 
36
#include <curl/mprintf.h>
 
37
 
 
38
/* The last #include file should be: */
 
39
#ifdef MALLOCDEBUG
 
40
#include "memdebug.h"
 
41
#endif
 
42
 
 
43
/* 
 
44
 * Chunk format (simplified):
 
45
 *
 
46
 * <HEX SIZE>[ chunk extension ] CRLF
 
47
 * <DATA> CRLF
 
48
 *
 
49
 * Highlights from RFC2616 section 3.6 say:
 
50
 
 
51
   The chunked encoding modifies the body of a message in order to
 
52
   transfer it as a series of chunks, each with its own size indicator,
 
53
   followed by an OPTIONAL trailer containing entity-header fields. This
 
54
   allows dynamically produced content to be transferred along with the
 
55
   information necessary for the recipient to verify that it has
 
56
   received the full message.
 
57
 
 
58
       Chunked-Body   = *chunk
 
59
                        last-chunk
 
60
                        trailer
 
61
                        CRLF
 
62
 
 
63
       chunk          = chunk-size [ chunk-extension ] CRLF
 
64
                        chunk-data CRLF
 
65
       chunk-size     = 1*HEX
 
66
       last-chunk     = 1*("0") [ chunk-extension ] CRLF
 
67
 
 
68
       chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
 
69
       chunk-ext-name = token
 
70
       chunk-ext-val  = token | quoted-string
 
71
       chunk-data     = chunk-size(OCTET)
 
72
       trailer        = *(entity-header CRLF)
 
73
 
 
74
   The chunk-size field is a string of hex digits indicating the size of
 
75
   the chunk. The chunked encoding is ended by any chunk whose size is
 
76
   zero, followed by the trailer, which is terminated by an empty line.
 
77
 
 
78
 */
 
79
 
 
80
 
 
81
void Curl_httpchunk_init(struct connectdata *conn)
 
82
{
 
83
  struct Curl_chunker *chunk = &conn->proto.http->chunk;
 
84
  chunk->hexindex=0; /* start at 0 */
 
85
  chunk->dataleft=0; /* no data left yet! */
 
86
  chunk->state = CHUNK_HEX; /* we get hex first! */
 
87
}
 
88
 
 
89
/*
 
90
 * chunk_read() returns a OK for normal operations, or a positive return code
 
91
 * for errors. STOP means this sequence of chunks is complete.  The 'wrote'
 
92
 * argument is set to tell the caller how many bytes we actually passed to the
 
93
 * client (for byte-counting and whatever).
 
94
 *
 
95
 * The states and the state-machine is further explained in the header file.
 
96
 */
 
97
CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
 
98
                              char *datap,
 
99
                              size_t length,
 
100
                              size_t *wrote)
 
101
{
 
102
  CURLcode result;
 
103
  struct Curl_chunker *ch = &conn->proto.http->chunk;
 
104
  int piece;
 
105
  *wrote = 0; /* nothing yet */
 
106
 
 
107
  while(length) {
 
108
    switch(ch->state) {
 
109
    case CHUNK_HEX:
 
110
      if(isxdigit((int)*datap)) {
 
111
        if(ch->hexindex < MAXNUM_SIZE) {
 
112
          ch->hexbuffer[ch->hexindex] = *datap;
 
113
          datap++;
 
114
          length--;
 
115
          ch->hexindex++;
 
116
        }
 
117
        else {
 
118
          return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */
 
119
        }
 
120
      }
 
121
      else {
 
122
        if(0 == ch->hexindex) {
 
123
          /* This is illegal data, we received junk where we expected
 
124
             a hexadecimal digit. */
 
125
          return CHUNKE_ILLEGAL_HEX;
 
126
        }
 
127
        /* length and datap are unmodified */
 
128
        ch->hexbuffer[ch->hexindex]=0;
 
129
        ch->datasize=strtoul(ch->hexbuffer, NULL, 16);
 
130
        ch->state = CHUNK_POSTHEX;
 
131
      }
 
132
      break;
 
133
 
 
134
    case CHUNK_POSTHEX:
 
135
      /* In this state, we're waiting for CRLF to arrive. We support
 
136
         this to allow so called chunk-extensions to show up here
 
137
         before the CRLF comes. */
 
138
      if(*datap == '\r')
 
139
        ch->state = CHUNK_CR;
 
140
      length--;
 
141
      datap++;
 
142
      break;
 
143
 
 
144
    case CHUNK_CR:
 
145
      /* waiting for the LF */
 
146
      if(*datap == '\n') {
 
147
        /* we're now expecting data to come, unless size was zero! */
 
148
        if(0 == ch->datasize) {
 
149
          ch->state = CHUNK_STOP; /* stop reading! */
 
150
          if(1 == length) {
 
151
            /* This was the final byte, return right now */
 
152
            return CHUNKE_STOP;
 
153
          }
 
154
        }
 
155
        else
 
156
          ch->state = CHUNK_DATA;
 
157
      }
 
158
      else
 
159
        /* previously we got a fake CR, go back to CR waiting! */
 
160
        ch->state = CHUNK_CR;
 
161
      datap++;
 
162
      length--;
 
163
      break;
 
164
 
 
165
    case CHUNK_DATA:
 
166
      /* we get pure and fine data
 
167
 
 
168
         We expect another 'datasize' of data. We have 'length' right now,
 
169
         it can be more or less than 'datasize'. Get the smallest piece.
 
170
      */
 
171
      piece = (ch->datasize >= length)?length:ch->datasize;
 
172
 
 
173
      /* Write the data portion available */
 
174
      result = Curl_client_write(conn->data, CLIENTWRITE_BODY, datap, piece);
 
175
      if(result)
 
176
        return CHUNKE_WRITE_ERROR;
 
177
      *wrote += piece;
 
178
 
 
179
      ch->datasize -= piece; /* decrease amount left to expect */
 
180
      datap += piece;    /* move read pointer forward */
 
181
      length -= piece;   /* decrease space left in this round */
 
182
 
 
183
      if(0 == ch->datasize)
 
184
        /* end of data this round, we now expect a trailing CRLF */
 
185
        ch->state = CHUNK_POSTCR;
 
186
      break;
 
187
 
 
188
    case CHUNK_POSTCR:
 
189
      if(*datap == '\r') {
 
190
        ch->state = CHUNK_POSTLF;
 
191
        datap++;
 
192
        length--;
 
193
      }
 
194
      else
 
195
        return CHUNKE_BAD_CHUNK;
 
196
      break;
 
197
 
 
198
    case CHUNK_POSTLF:
 
199
      if(*datap == '\n') {
 
200
        /*
 
201
         * The last one before we go back to hex state and start all
 
202
         * over.
 
203
         */
 
204
        Curl_httpchunk_init(conn);
 
205
        datap++;
 
206
        length--;
 
207
      }
 
208
      else
 
209
        return CHUNKE_BAD_CHUNK;
 
210
      break;
 
211
 
 
212
    case CHUNK_STOP:
 
213
      /* If we arrive here, there is data left in the end of the buffer
 
214
         even if there's no more chunks to read */
 
215
      ch->dataleft = length;
 
216
      return CHUNKE_STOP; /* return stop */
 
217
    default:
 
218
      return CHUNKE_STATE_ERROR;
 
219
    }
 
220
  }
 
221
  return CHUNKE_OK;
 
222
}
 
223
 
 
224
/*
 
225
 * local variables:
 
226
 * eval: (load-file "../curl-mode.el")
 
227
 * end:
 
228
 * vim600: fdm=marker
 
229
 * vim: et sw=2 ts=2 sts=2 tw=78
 
230
 */