-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHttpWebRequestWrapper.cs
162 lines (149 loc) · 7.05 KB
/
HttpWebRequestWrapper.cs
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
using System;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
namespace WebRequest
{
/// <summary>
/// Exposes System.Net.WebRequest via COM.
/// </summary>
[ComVisible(true)]
[Guid("73A7A013-2249-4A59-8E3C-594E70A2D3C4")]
public class HttpWebRequestWrapper
{
/// <summary>
/// Regular Expression to parses content type and detect encodings
/// </summary>
private static readonly Regex _charSetRegex = new Regex(@"charset\s?\=\s?(?<charset>[^;]+);?",
RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
/// <summary>
/// Executes a web request against the specified URL.
/// </summary>
/// <param name="url">The URL.</param>
/// <param name="content">The content.</param>
/// <param name="method">The method.</param>
/// <param name="contentType">Type of the content.</param>
/// <param name="encoding">The encoding.</param>
/// <returns>The response from the URL.</returns>
/// <exception cref="System.ArgumentNullException">url - No URL was specified.</exception>
/// <exception cref="System.ArgumentException">url - URL is not a valid absolute HTTP(S) URI.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">Cannot specify content data when method is GET.</exception>
/// <exception cref="System.ApplicationException">Failed to create web request
/// or
/// URI did not return an OK response.</exception>
public string Execute(
string url,
string content = null,
string method = null,
string contentType = null,
string encoding = null)
{
/*
* Validate the Uri.
*/
url = url?.Trim();
if (string.IsNullOrEmpty(url))
throw new ArgumentNullException(nameof(url), "No URL was specified.");
Uri uri;
// Ensure URI is an absolute URI, has a valid syntax, and the scheme starts with 'http'.
if (!Uri.TryCreate(url, UriKind.Absolute, out uri) ||
!uri.Scheme.StartsWith("http", StringComparison.InvariantCultureIgnoreCase))
throw new ArgumentException($"\"{url}\" is not a valid absolute HTTP(S) URI.", nameof(url));
// Normalise method
method = string.IsNullOrWhiteSpace(method) ? "POST" : method.Trim();
// Ensure content is null if attempting a GET.
if (content != null && string.Equals(method, "GET", StringComparison.InvariantCultureIgnoreCase))
throw new ArgumentOutOfRangeException(nameof(content), "Cannot specify content data when method is GET.");
// Normalise content Type. Dismiss the Encoding.
GetEncoding(ref contentType, ref encoding);
// Create a .NET 4 web request, to ensure we can connect without InProc SxS
HttpWebRequest webRequest = System.Net.WebRequest.Create(uri) as HttpWebRequest;
if (webRequest == null)
throw new ApplicationException("Failed to create web request");
webRequest.Method = method;
// If we have content then write it.
if (content != null)
{
webRequest.ContentType = contentType;
webRequest.ContentLength = content.Length;
/*
* STACK OVERFLOW OCCURS WHILST CALLING GetRequestStream() BELOW
*/
using (StreamWriter sw = new StreamWriter(webRequest.GetRequestStream()))
sw.Write(content);
}
// Get the response
string response;
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
using (StreamReader reader = new StreamReader(webResponse.GetResponseStream()))
response = reader.ReadToEnd();
return response;
}
/// <summary>
/// Gets the encoding, and normalises the content type and encoding name.
/// </summary>
/// <param name="contentType">Type of the content.</param>
/// <param name="encoding">The encoding.</param>
/// <returns></returns>
private Encoding GetEncoding(ref string contentType, ref string encoding)
{
Encoding result = null;
if (!string.IsNullOrWhiteSpace(encoding))
{
// We have a named encoding - try to find it.
result = Encoding.GetEncoding(encoding);
// Correct any encoding in the content type
encoding = result.WebName;
string charSet = $"charset={encoding}";
if (string.IsNullOrWhiteSpace(contentType))
contentType = $"application/x-www-form-urlencoded;{charSet}";
else
{
bool matched = false;
// ReSharper disable once PossibleNullReferenceException
contentType = _charSetRegex.Replace(contentType, m =>
{
if (matched) return string.Empty;
matched = true;
// ReSharper disable once PossibleNullReferenceException
return charSet + (m.Value[m.Value.Length - 1] == ';' ? ";" : string.Empty);
});
// ReSharper disable once PossibleNullReferenceException
if (!matched) contentType += (contentType[contentType.Length - 1] == ';' ? string.Empty : ";") + charSet;
}
}
else if (!string.IsNullOrWhiteSpace(contentType))
{
// See if the encoding is in the content type
bool matched = false;
// ReSharper disable once PossibleNullReferenceException
contentType = _charSetRegex.Replace(contentType, m =>
{
if (matched) return string.Empty;
matched = true;
string enc = m.Groups["charset"].Value.Trim().ToLowerInvariant();
result = Encoding.GetEncoding(enc);
return $"charset={result.WebName}" + (m.Value[m.Value.Length - 1] == ';' ? ";" : string.Empty);
});
if (!matched)
{
// Use default encoding
result = Encoding.UTF8;
contentType += (contentType[contentType.Length - 1] == ';' ? string.Empty : ";") + "charset=utf-8";
}
// ReSharper disable once PossibleNullReferenceException
encoding = result.WebName;
}
else
{
// Use defaults
result = Encoding.UTF8;
encoding = result.WebName;
contentType = "application/x-www-form-urlencoded;charset=utf-8";
}
return result;
}
}
}