1
2
3
4
5
6 using System;
7 using System.Collections;
8 using System.IO;
9 using System.Net.Sockets;
10 using System.IO.Compression;
11
12 namespace System.Net.Http
13 {
14 public class HttpClient
15 {
16 public HttpClient() : baseAddress(), tcpClient(), stream(), log(null)
17 {
18 }
19 public HttpClient(const UriReference& baseAddress_) : baseAddress(baseAddress_), tcpClient(), stream(), log(null)
20 {
21 Connect();
22 }
23 public HttpClient(const UriReference& baseAddress_, StreamWriter* log_) : baseAddress(baseAddress_), tcpClient(), stream(), log(log_)
24 {
25 Connect();
26 }
27 public void Connect()
28 {
29 Connect(baseAddress.GetAuthority().Host(), baseAddress.Scheme());
30 }
31 public void Connect(const string& node, const string& service)
32 {
33 if (log != null)
34 {
35 log->WriteLine("Connecting to host '" + node + "', service '" + service + "'...");
36 }
37 tcpClient.Connect(node, service);
38 stream = tcpClient.GetStream();
39 if (log != null)
40 {
41 log->WriteLine("Connected to host '" + node + "', service '" + service + "'");
42 }
43 }
44 public HttpStatus Get(const UriReference& uri, HttpHeaderCollection& responseHeaders, SharedPtr<ByteStream>& body)
45 {
46 HttpHeaderCollection requestHeaders;
47 return Get(uri, requestHeaders, responseHeaders, body);
48 }
49 public HttpStatus Get(const UriReference& uri, HttpHeaderCollection& requestHeaders, HttpHeaderCollection& responseHeaders, SharedPtr<ByteStream>& body)
50 {
51 responseHeaders.Clear();
52 UriReference absoluteUri = UriReference.Combine(baseAddress, uri);
53 if (absoluteUri.GetAuthority().Host() != baseAddress.GetAuthority().Host() || absoluteUri.Scheme() != baseAddress.Scheme())
54 {
55 Connect(absoluteUri.GetAuthority().Host(), absoluteUri.Scheme());
56 }
57 HttpRequest request(absoluteUri, requestHeaders);
58 StreamWriter writer(stream);
59 request.Write(writer, log);
60 HttpStatus status = ReadStartOfMessage(*stream, responseHeaders, log);
61 if (status.StatusCode() == statusRedirectionMovedPermanently)
62 {
63 HttpHeader* locationHeader = responseHeaders.GetHeader("location");
64 string location = locationHeader->SingleFieldValue().FieldValue();
65 UriReference locationUri(location);
66 return Get(locationUri, requestHeaders, responseHeaders, body);
67 }
68 else if (status.StatusCode() == statusSuccessOK)
69 {
70 bool chunked = false;
71 HttpHeader* transferEncodingHeader = responseHeaders.GetHeader("transfer-encoding");
72 if (transferEncodingHeader != null)
73 {
74 string transferCodingsValue = transferEncodingHeader->CombinedFieldValue();
75 List<HttpFieldValue> transferCodings;
76 HttpParser.ParseFieldValue(transferCodingsValue, &transferCodings);
77 for (const HttpFieldValue& transferCoding : transferCodings)
78 {
79 if (ToLower(transferCoding.FieldValue()) == "chunked")
80 {
81 chunked = true;
82 }
83 }
84 }
85 if (chunked)
86 {
87 List<HttpHeader> trailer;
88 SharedPtr<ByteStream> bodyStream = ReadChunkedBody(*stream, trailer);
89 for (const HttpHeader& header : trailer)
90 {
91 responseHeaders.Add(UniquePtr<HttpHeader>(new HttpHeader(header)));
92 }
93 body = bodyStream;
94 }
95 else
96 {
97 body = stream;
98 }
99 }
100 return status;
101 }
102 public inline nothrow const UriReference& BaseAddress() const
103 {
104 return baseAddress;
105 }
106 public void SetBaseAddress(const UriReference& baseAddress_)
107 {
108 baseAddress = baseAddress_;
109 }
110 public inline nothrow void SetLog(StreamWriter* log_)
111 {
112 log = log_;
113 }
114 private UriReference baseAddress;
115 private TcpClient tcpClient;
116 private SharedPtr<ByteStream> stream;
117 private StreamWriter* log;
118 }
119 }