~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/netwerk/protocol/http/src/nsHttpChunkedDecoder.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 
2
/*
 
3
 * The contents of this file are subject to the Mozilla Public
 
4
 * License Version 1.1 (the "License"); you may not use this file
 
5
 * except in compliance with the License. You may obtain a copy of
 
6
 * the License at http://www.mozilla.org/MPL/
 
7
 * 
 
8
 * Software distributed under the License is distributed on an "AS
 
9
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
10
 * implied. See the License for the specific language governing
 
11
 * rights and limitations under the License.
 
12
 * 
 
13
 * The Original Code is Mozilla.
 
14
 * 
 
15
 * The Initial Developer of the Original Code is Netscape
 
16
 * Communications.  Portions created by Netscape Communications are
 
17
 * Copyright (C) 2001 by Netscape Communications.  All
 
18
 * Rights Reserved.
 
19
 * 
 
20
 * Contributor(s): 
 
21
 *   Darin Fisher <darin@netscape.com> (original author)
 
22
 */
 
23
 
 
24
#include "nsHttpChunkedDecoder.h"
 
25
#include "nsHttp.h"
 
26
 
 
27
//-----------------------------------------------------------------------------
 
28
// nsHttpChunkedDecoder <public>
 
29
//-----------------------------------------------------------------------------
 
30
 
 
31
nsresult
 
32
nsHttpChunkedDecoder::HandleChunkedContent(char *buf,
 
33
                                           PRUint32 count,
 
34
                                           PRUint32 *contentRead,
 
35
                                           PRUint32 *contentRemaining)
 
36
{
 
37
    LOG(("nsHttpChunkedDecoder::HandleChunkedContent [count=%u]\n", count));
 
38
 
 
39
    *contentRead = 0;
 
40
    
 
41
    // from RFC2617 section 3.6.1, the chunked transfer coding is defined as:
 
42
    //
 
43
    //   Chunked-Body    = *chunk
 
44
    //                     last-chunk
 
45
    //                     trailer
 
46
    //                     CRLF
 
47
    //   chunk           = chunk-size [ chunk-extension ] CRLF
 
48
    //                     chunk-data CRLF
 
49
    //   chunk-size      = 1*HEX
 
50
    //   last-chunk      = 1*("0") [ chunk-extension ] CRLF
 
51
    //       
 
52
    //   chunk-extension = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
 
53
    //   chunk-ext-name  = token
 
54
    //   chunk-ext-val   = token | quoted-string
 
55
    //   chunk-data      = chunk-size(OCTET)
 
56
    //   trailer         = *(entity-header CRLF)
 
57
    //
 
58
    // the chunk-size field is a string of hex digits indicating the size of the
 
59
    // chunk.  the chunked encoding is ended by any chunk whose size is zero, 
 
60
    // followed by the trailer, which is terminated by an empty line.
 
61
 
 
62
    while (count) {
 
63
        if (mChunkRemaining) {
 
64
            PRUint32 amt = PR_MIN(mChunkRemaining, count);
 
65
 
 
66
            count -= amt;
 
67
            mChunkRemaining -= amt;
 
68
 
 
69
            *contentRead += amt;
 
70
            buf += amt;
 
71
        }
 
72
        else if (mReachedEOF)
 
73
            break; // done
 
74
        else {
 
75
            PRUint32 bytesConsumed = 0;
 
76
 
 
77
            nsresult rv = ParseChunkRemaining(buf, count, &bytesConsumed);
 
78
            if (NS_FAILED(rv)) return rv;
 
79
 
 
80
            count -= bytesConsumed;
 
81
 
 
82
            if (count) {
 
83
                // shift buf by bytesConsumed
 
84
                memmove(buf, buf + bytesConsumed, count);
 
85
            }
 
86
        }
 
87
    }
 
88
    
 
89
    *contentRemaining = count;
 
90
    return NS_OK;
 
91
}
 
92
 
 
93
//-----------------------------------------------------------------------------
 
94
// nsHttpChunkedDecoder <private>
 
95
//-----------------------------------------------------------------------------
 
96
 
 
97
nsresult
 
98
nsHttpChunkedDecoder::ParseChunkRemaining(char *buf,
 
99
                                          PRUint32 count,
 
100
                                          PRUint32 *bytesConsumed)
 
101
{
 
102
    NS_PRECONDITION(mChunkRemaining == 0, "chunk remaining should be zero");
 
103
    NS_PRECONDITION(count, "unexpected");
 
104
 
 
105
    *bytesConsumed = 0;
 
106
    
 
107
    char *p = NS_STATIC_CAST(char *, memchr(buf, '\n', count));
 
108
    if (p) {
 
109
        *p = 0;
 
110
        if ((p > buf) && (*(p-1) == '\r')) // eliminate a preceding CR
 
111
            *(p-1) = 0;
 
112
        *bytesConsumed = p - buf + 1;
 
113
 
 
114
        // make buf point to the full line buffer to parse
 
115
        if (!mLineBuf.IsEmpty()) {
 
116
            mLineBuf.Append(buf);
 
117
            buf = (char *) mLineBuf.get();
 
118
        }
 
119
 
 
120
        if (mWaitEOF) {
 
121
            if (*buf) {
 
122
                LOG(("got trailer: %s\n", buf));
 
123
                // allocate a header array for the trailers on demand
 
124
                if (!mTrailers) {
 
125
                    mTrailers = new nsHttpHeaderArray();
 
126
                    if (!mTrailers)
 
127
                        return NS_ERROR_OUT_OF_MEMORY;
 
128
                }
 
129
                mTrailers->ParseHeaderLine(buf);
 
130
            }
 
131
            else {
 
132
                mWaitEOF = PR_FALSE;
 
133
                mReachedEOF = PR_TRUE;
 
134
                LOG(("reached end of chunked-body\n"));
 
135
            }
 
136
        }
 
137
        else if (*buf) {
 
138
            // ignore any chunk-extensions
 
139
            if ((p = PL_strchr(buf, ';')) != nsnull)
 
140
                *p = 0;
 
141
 
 
142
            if (!sscanf(buf, "%x", &mChunkRemaining)) {
 
143
                LOG(("sscanf failed parsing hex on string [%s]\n", buf));
 
144
                return NS_ERROR_UNEXPECTED;
 
145
            }
 
146
 
 
147
            // we've discovered the last chunk
 
148
            if (mChunkRemaining == 0)
 
149
                mWaitEOF = PR_TRUE;
 
150
        }
 
151
 
 
152
        // ensure that the line buffer is clear
 
153
        mLineBuf.Truncate();
 
154
    }
 
155
    else {
 
156
        // save the partial line; wait for more data
 
157
        *bytesConsumed = count;
 
158
        // ignore a trailing CR
 
159
        if (buf[count-1] == '\r')
 
160
            count--;
 
161
        mLineBuf.Append(buf, count);
 
162
    }
 
163
 
 
164
    return NS_OK;
 
165
}