1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  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& nodeconst string& service)
 32         {
 33             if (log != null)
 34             {
 35                 log->WriteLine("Connecting to host '" + node + "', service '" + service + "'...");
 36             }
 37             tcpClient.Connect(nodeservice);
 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& uriHttpHeaderCollection& responseHeadersSharedPtr<ByteStream>& body)
 45         {
 46             HttpHeaderCollection requestHeaders;
 47             return Get(urirequestHeadersresponseHeadersbody);
 48         }
 49         public HttpStatus Get(const UriReference& uriHttpHeaderCollection& requestHeadersHttpHeaderCollection& responseHeadersSharedPtr<ByteStream>& body)
 50         {
 51             responseHeaders.Clear();
 52             UriReference absoluteUri = UriReference.Combine(baseAddressuri);
 53             if (absoluteUri.GetAuthority().Host() != baseAddress.GetAuthority().Host() || absoluteUri.Scheme() != baseAddress.Scheme())
 54             {
 55                 Connect(absoluteUri.GetAuthority().Host()absoluteUri.Scheme());
 56             }
 57             HttpRequest request(absoluteUrirequestHeaders);
 58             StreamWriter writer(stream);
 59             request.Write(writerlog);
 60             HttpStatus status = ReadStartOfMessage(*streamresponseHeaderslog);
 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(locationUrirequestHeadersresponseHeadersbody);
 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(*streamtrailer);
 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 }