-
Notifications
You must be signed in to change notification settings - Fork 83
Expand file tree
/
Copy pathHttpHeader.cs
More file actions
303 lines (266 loc) · 9.27 KB
/
HttpHeader.cs
File metadata and controls
303 lines (266 loc) · 9.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
using System.Collections.Generic;
using Waher.Networking.HTTP.HeaderFields;
using Waher.Networking.HTTP.Vanity;
namespace Waher.Networking.HTTP
{
/// <summary>
/// Contains information about all fields in an HTTP header.
/// </summary>
public abstract class HttpHeader : ICollection<HttpField>
{
/// <summary>
/// HTTP fields.
/// </summary>
protected Dictionary<string, HttpField> fields = new Dictionary<string, HttpField>();
private HttpFieldContentEncoding contentEncoding = null;
private HttpFieldContentLanguage contentLanguage = null;
private HttpFieldContentLength contentLength = null;
private HttpFieldContentLocation contentLocation = null;
private HttpFieldContentMD5 contentMD5 = null;
private HttpFieldContentRange contentRange = null;
private HttpFieldContentType contentType = null;
private HttpFieldTransferEncoding transferEncoding = null;
private HttpFieldVia via = null;
/// <summary>
/// Contains information about all fields in an HTTP header.
/// </summary>
public HttpHeader()
{
}
/// <summary>
/// Contains information about all fields in an HTTP header.
/// </summary>
/// <param name="Header">HTTP Header.</param>
/// <param name="VanityResources">Registered vanity resources.</param>
public HttpHeader(string Header, VanityResources VanityResources)
{
HttpField Field;
string Key;
string KeyLower;
string Value;
int i;
bool First = true;
foreach (string Row in Header.Replace("\r\n", "\n").Replace("\r", "\n").Split('\n'))
{
if (First)
{
if (!string.IsNullOrEmpty(Row))
{
First = false;
this.ParseFirstRow(Row, VanityResources);
}
}
else
{
i = Row.IndexOf(':');
if (i < 0)
continue;
Key = Row.Substring(0, i).Trim();
Value = Row.Substring(i + 1).Trim();
Field = this.ParseField(KeyLower = Key.ToLower(), Key, Value);
this.fields[KeyLower] = Field;
}
}
}
/// <summary>
/// Adds a field to the header.
/// </summary>
/// <param name="Key">Header key (or name).</param>
/// <param name="Value">Header value.</param>
/// <param name="IsLower">If <paramref name="Key"/> is lowercase already.</param>
public void AddField(string Key, string Value, bool IsLower)
{
string s = IsLower ? Key : Key.ToLower();
HttpField Field = this.ParseField(s, Key, Value);
this.fields[s] = Field;
}
/// <summary>
/// Contains information about all fields in an HTTP header.
/// </summary>
/// <param name="FirstRow">First row.</param>
/// <param name="VanityResources">Registered vanity resources.</param>
/// <param name="Headers">Headers.</param>
public HttpHeader(string FirstRow, VanityResources VanityResources, params KeyValuePair<string, string>[] Headers)
{
HttpField Field;
string KeyLower;
this.ParseFirstRow(FirstRow, VanityResources);
foreach (KeyValuePair<string, string> P in Headers)
{
Field = this.ParseField(KeyLower = P.Key.ToLower(), P.Key, P.Value);
this.fields[KeyLower] = Field;
}
}
/// <summary>
/// Parses the first row of an HTTP header.
/// </summary>
/// <param name="Row">First row.</param>
/// <param name="VanityResources">Registered vanity resources.</param>
protected abstract void ParseFirstRow(string Row, VanityResources VanityResources);
/// <summary>
/// Access to individual fields.
/// </summary>
/// <param name="Key">HTTP header field name.</param>
/// <returns>Header value, if found, or the empty string, if not found.</returns>
public string this[string Key]
{
get
{
if (this.fields.TryGetValue(Key.ToLower(), out HttpField Field))
return Field.Value;
else
return string.Empty;
}
}
/// <summary>
/// Parses a specific HTTP header field.
/// </summary>
/// <param name="KeyLower">Lower-case version of field name.</param>
/// <param name="Key">Field name, as it appears in the header.</param>
/// <param name="Value">Unparsed header field value</param>
/// <returns>HTTP header field object, corresponding to the particular field.</returns>
protected virtual HttpField ParseField(string KeyLower, string Key, string Value)
{
switch (KeyLower)
{
case "content-encoding": return this.contentEncoding = new HttpFieldContentEncoding(Key, Value);
case "content-language": return this.contentLanguage = new HttpFieldContentLanguage(Key, Value);
case "content-length": return this.contentLength = new HttpFieldContentLength(Key, Value);
case "content-location": return this.contentLocation = new HttpFieldContentLocation(Key, Value);
case "content-md5": return this.contentMD5 = new HttpFieldContentMD5(Key, Value);
case "content-range": return this.contentRange = new HttpFieldContentRange(Key, Value);
case "content-type": return this.contentType = new HttpFieldContentType(Key, Value);
case "transfer-encoding": return this.transferEncoding = new HttpFieldTransferEncoding(Key, Value);
case "via": return this.via = new HttpFieldVia(Key, Value);
default: return new HttpField(Key, Value);
};
}
#region ICollection<HttpField>
/// <summary>
/// Adds an HTTP field
/// </summary>
public void Add(HttpField item)
{
this.fields[item.Key.ToLower()] = item;
}
/// <summary>
/// Clears the collection of HTTP fields.
/// </summary>
public void Clear()
{
this.fields.Clear();
}
/// <summary>
/// Checks if the header contains a field having the same Key and Value properties as <paramref name="item"/>.
/// </summary>
/// <param name="item">HTTP header field.</param>
/// <returns>If a similar HTTP header field exists in the collection.</returns>
public bool Contains(HttpField item)
{
return (this.fields.TryGetValue(item.Key.ToLower(), out HttpField Field) && Field.Value == item.Value);
}
/// <summary>
/// Copies the collection of HTTP header fields to an array.
/// </summary>
/// <param name="array">Array to copy to.</param>
/// <param name="arrayIndex">Offset into array where first element is copied to.</param>
public void CopyTo(HttpField[] array, int arrayIndex)
{
this.fields.Values.CopyTo(array, arrayIndex);
}
/// <summary>
/// Number of HTTP fields in the collection.
/// </summary>
public int Count
{
get { return this.fields.Count; }
}
/// <summary>
/// If the collection is read-only.
/// </summary>
public bool IsReadOnly
{
get { return false; }
}
/// <summary>
/// Removes a field having the same Key and Value properties as <paramref name="item"/>.
/// </summary>
/// <param name="item">HTTP header field.</param>
/// <returns>If such a field was found and removed.</returns>
public bool Remove(HttpField item)
{
string Key;
if (this.fields.TryGetValue(Key = item.Key.ToLower(), out HttpField Field) && Field.Value == item.Value)
return this.fields.Remove(Key);
else
return false;
}
/// <summary>
/// Gets an enumerator of available HTTP header fields.
/// </summary>
/// <returns>Enumerator object.</returns>
public IEnumerator<HttpField> GetEnumerator()
{
return this.fields.Values.GetEnumerator();
}
/// <summary>
/// Gets an enumerator of available HTTP header fields.
/// </summary>
/// <returns>Enumerator object.</returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.fields.Values.GetEnumerator();
}
#endregion
/// <summary>
/// Tries to get a named header field.
/// </summary>
/// <param name="FieldName">Name of field.</param>
/// <param name="Field">Field, if found.</param>
/// <returns>If the corresponding field was found in the header.</returns>
public bool TryGetHeaderField(string FieldName, out HttpField Field)
{
return this.fields.TryGetValue(FieldName.ToLower(), out Field);
}
/// <summary>
/// Content-Encoding HTTP Field header. (RFC 2616, §14.11)
/// </summary>
public HttpFieldContentEncoding ContentEncoding => this.contentEncoding;
/// <summary>
/// Content-Language HTTP Field header. (RFC 2616, §14.12)
/// </summary>
public HttpFieldContentLanguage ContentLanguage => this.contentLanguage;
/// <summary>
/// Content-Length HTTP Field header. (RFC 2616, §14.13)
/// </summary>
public HttpFieldContentLength ContentLength => this.contentLength;
/// <summary>
/// Content-Location HTTP Field header. (RFC 2616, §14.14)
/// </summary>
public HttpFieldContentLocation ContentLocation => this.contentLocation;
/// <summary>
/// Content-MD5 HTTP Field header. (RFC 2616, §14.15)
/// </summary>
public HttpFieldContentMD5 ContentMD5 => this.contentMD5;
/// <summary>
/// Content-Range HTTP Field header. (RFC 2616, §14.16)
/// </summary>
public HttpFieldContentRange ContentRange => this.contentRange;
/// <summary>
/// Content-Type HTTP Field header. (RFC 2616, §14.17)
/// </summary>
public HttpFieldContentType ContentType => this.contentType;
/// <summary>
/// Transfer-Encoding HTTP Field header. (RFC 2616, §14.41)
/// </summary>
public HttpFieldTransferEncoding TransferEncoding => this.transferEncoding;
/// <summary>
/// Via HTTP Field header. (RFC 2616, §14.45)
/// </summary>
public HttpFieldVia Via => this.via;
/// <summary>
/// If the message contains, apart from the header, a message body also.
/// </summary>
public abstract bool HasMessageBody { get; }
}
}