using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
namespace dotnetcore.utils
{
///
/// Various Http helper routines
///
public static class HttpHelpers
{
///
/// Makes a http request to the specified endpoint
///
///
///
///
///
public static void InvokeHttpRequest(Uri endpointUri,
string httpMethod,
IDictionary headers,
string requestBody)
{
try
{
var request = ConstructWebRequest(endpointUri, httpMethod, headers);
if (!string.IsNullOrEmpty(requestBody))
{
var buffer = new byte[8192]; // arbitrary buffer size
var requestStream = request.GetRequestStream();
using (var inputStream = new MemoryStream(Encoding.UTF8.GetBytes(requestBody)))
{
var bytesRead = 0;
while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
requestStream.Write(buffer, 0, bytesRead);
}
}
}
GetResponse(request);
}
catch (WebException ex)
{
using (var response = ex.Response as HttpWebResponse)
{
if (response != null)
{
var errorMsg = ReadResponseBody(response);
Logger.LogError($"\n-- HTTP call failed with exception '{errorMsg}', status code '{response.StatusCode}'");
}
}
}
}
///
/// Construct a HttpWebRequest onto the specified endpoint and populate
/// the headers.
///
/// The endpoint to call
/// GET, PUT etc
/// The set of headers to apply to the request
/// Initialized HttpWebRequest instance
public static HttpWebRequest ConstructWebRequest(Uri endpointUri,
string httpMethod,
IDictionary headers)
{
var request = (HttpWebRequest)WebRequest.Create(endpointUri);
request.Method = httpMethod;
foreach (var header in headers.Keys)
{
// not all headers can be set via the dictionary
if (header.Equals("host", StringComparison.OrdinalIgnoreCase))
request.Host = headers[header];
else if (header.Equals("content-length", StringComparison.OrdinalIgnoreCase))
request.ContentLength = long.Parse(headers[header]);
else if (header.Equals("content-type", StringComparison.OrdinalIgnoreCase))
request.ContentType = headers[header];
else
request.Headers.Add(header, headers[header]);
}
return request;
}
public static HttpWebResponse GetResponse(HttpWebRequest request)
{
// Get the response and read any body into a string, then display.
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.StatusCode == HttpStatusCode.OK)
{
Logger.LogDebug("\n-- HTTP call succeeded");
var responseBody = ReadResponseBody(response);
if (!string.IsNullOrEmpty(responseBody))
{
Logger.LogDebug("\n-- Response body:");
Logger.LogDebug(responseBody);
}
}
else
Logger.LogDebug($"\n-- HTTP call failed, status code: {response.StatusCode}");
return response;
}
}
///
/// Reads the response data from the service call, if any
///
///
/// The response instance obtained from the previous request
///
/// The body content of the response
public static string ReadResponseBody(HttpWebResponse response)
{
if (response == null)
throw new ArgumentNullException("response", "Value cannot be null");
// Then, open up a reader to the response and read the contents to a string
// and return that to the caller.
string responseBody = string.Empty;
using (var responseStream = response.GetResponseStream())
{
if (responseStream != null)
{
using (var reader = new StreamReader(responseStream))
{
responseBody = reader.ReadToEnd();
}
}
}
return responseBody;
}
///
/// Helper routine to url encode canonicalized header names and values for safe
/// inclusion in the presigned url.
///
/// The string to encode
/// Whether the string is a URL path or not
/// The encoded string
public static string UrlEncode(string data, bool isPath = false)
{
// The Set of accepted and valid Url characters per RFC3986. Characters outside of this set will be encoded.
const string validUrlCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
var encoded = new StringBuilder(data.Length * 2);
string unreservedChars = String.Concat(validUrlCharacters, (isPath ? "/:" : ""));
foreach (char symbol in System.Text.Encoding.UTF8.GetBytes(data))
{
if (unreservedChars.IndexOf(symbol) != -1)
encoded.Append(symbol);
else
encoded.Append("%").Append(String.Format("{0:X2}", (int)symbol));
}
return encoded.ToString();
}
}
}