1
2
3
4
5
6 using System;
7 using System.IO;
8 using System.Collections;
9 using System.Concepts;
10
11 namespace System.Net.Http
12 {
13 public class ChunkExtensionAdder
14 {
15 public ChunkExtensionAdder(Map<string, string>& chunkExtensions_) : chunkExtensions(chunkExtensions_)
16 {
17 }
18 public void AddChunkExtension(const string& chunkExtName, const string& chunkExtVal)
19 {
20 chunkExtensions[chunkExtName] = chunkExtVal;
21 }
22 private Map<string, string>& chunkExtensions;
23 }
24
25 public void ReadCRLF(ByteStream& stream)
26 {
27 int x = stream.ReadByte();
28 if (x != 13)
29 {
30 throw Exception("CR expected");
31 }
32 x = stream.ReadByte();
33 if (x != 10)
34 {
35 throw Exception("LF expected");
36 }
37 }
38
39 public ulong ReadChunkHeader(ByteStream& stream, Map<string, string>& chunkExtensions)
40 {
41 string s;
42 int x = stream.ReadByte();
43 int state = 0;
44 while (x != -1)
45 {
46 byte b = cast<byte>(x);
47 switch (state)
48 {
49 case 0:
50 {
51 if (b == 13u)
52 {
53 state = 1;
54 }
55 else
56 {
57 s.Append(cast<char>(b));
58 }
59 break;
60 }
61 case 1:
62 {
63 if (b == 10u)
64 {
65 ulong chunkSize = 0u;
66 ChunkExtensionAdder adder(chunkExtensions);
67 HttpParser.ParseChunkHeader(s, &chunkSize, &adder);
68 return chunkSize;
69 }
70 else if (b != 13u)
71 {
72 state = 0;
73 }
74 break;
75 }
76 }
77 x = stream.ReadByte();
78 }
79 throw HttpException(HttpStatus("HTTP/1.1", statusClientErrorBadRequest, "invalid HTTP message"));
80 }
81
82 public void ReadTrailer(ByteStream& stream, List<HttpHeader>& trailer)
83 {
84 string line;
85 int x = stream.ReadByte();
86 int state = 0;
87 while (x != -1)
88 {
89 byte b = cast<byte>(x);
90 switch (state)
91 {
92 case 0:
93 {
94 if (b == 13u)
95 {
96 state = 1;
97 }
98 else
99 {
100 line.Append(cast<char>(b));
101 state = 2;
102 }
103 break;
104 }
105 case 1:
106 {
107 if (b == 10u)
108 {
109 return;
110 }
111 else if (b != 13u)
112 {
113 line.Append(cast<char>(13));
114 line.Append(cast<char>(b));
115 state = 2;
116 }
117 break;
118 }
119 case 2:
120 {
121 if (b == 13u)
122 {
123 state = 3;
124 }
125 else
126 {
127 line.Append(cast<char>(b));
128 }
129 break;
130 }
131 case 3:
132 {
133 if (b == 10u)
134 {
135 if (!line.IsEmpty())
136 {
137 HttpHeader header = HttpParser.ParseHeader(line);
138 trailer.Add(header);
139 line.Clear();
140 }
141 state = 0;
142 }
143 else if (b != 13u)
144 {
145 line.Append(cast<char>(13));
146 line.Append(cast<char>(b));
147 state = 2;
148 }
149 else
150 {
151 line.Append(cast<char>(13));
152 }
153 break;
154 }
155 }
156 x = stream.ReadByte();
157 }
158 throw HttpException(HttpStatus("HTTP/1.1", statusClientErrorBadRequest, "invalid HTTP message"));
159 }
160
161 public SharedPtr<ByteStream> ReadChunkedBody(ByteStream& stream, List<HttpHeader>& trailer)
162 {
163 SharedPtr<ByteStream> resultStream(new BufferedByteStream(SharedPtr<ByteStream>(new MemoryByteStream())));
164 Map<string, string> firstChunkExtensions;
165 ulong chunkSize = ReadChunkHeader(stream, firstChunkExtensions);
166 while (chunkSize != 0u)
167 {
168 for (ulong i = 0u; i < chunkSize; ++i;)
169 {
170 int x = stream.ReadByte();
171 if (x == -1)
172 {
173 throw Exception("unexpected end of stream");
174 }
175 byte b = cast<byte>(x);
176 resultStream->Write(b);
177 }
178 ReadCRLF(stream);
179 Map<string, string> nextChunkExtensions;
180 chunkSize = ReadChunkHeader(stream, nextChunkExtensions);
181 }
182 ReadTrailer(stream, trailer);
183 return resultStream;
184 }
185 }