aboutsummaryrefslogtreecommitdiff
path: root/RSSDP/HttpParserBase.cs
diff options
context:
space:
mode:
authorcrobibero <cody@robibe.ro>2020-09-11 15:53:04 -0600
committercrobibero <cody@robibe.ro>2020-09-11 15:53:04 -0600
commitf13b87afa3e81e7fa2710caec58a7d6cb20f7635 (patch)
tree0f269ac5baa27b334c5377d9dec4010aedf25183 /RSSDP/HttpParserBase.cs
parent2363ad544979adf32207fa927f106fadb784f1fb (diff)
parent6bf0acb854683377bebad3ca27de17706519c420 (diff)
Merge remote-tracking branch 'upstream/master' into api-upload-subtitle
Diffstat (limited to 'RSSDP/HttpParserBase.cs')
-rw-r--r--RSSDP/HttpParserBase.cs80
1 files changed, 51 insertions, 29 deletions
diff --git a/RSSDP/HttpParserBase.cs b/RSSDP/HttpParserBase.cs
index 773a06cdb..a40612bc2 100644
--- a/RSSDP/HttpParserBase.cs
+++ b/RSSDP/HttpParserBase.cs
@@ -11,16 +11,9 @@ namespace Rssdp.Infrastructure
/// <typeparam name="T"></typeparam>
public abstract class HttpParserBase<T> where T : new()
{
-
- #region Fields
-
private readonly string[] LineTerminators = new string[] { "\r\n", "\n" };
private readonly char[] SeparatorCharacters = new char[] { ',', ';' };
- #endregion
-
- #region Public Methods
-
/// <summary>
/// Parses the <paramref name="data"/> provided into either a <see cref="HttpRequestMessage"/> or <see cref="HttpResponseMessage"/> object.
/// </summary>
@@ -38,15 +31,26 @@ namespace Rssdp.Infrastructure
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification = "Honestly, it's fine. MemoryStream doesn't mind.")]
protected virtual void Parse(T message, System.Net.Http.Headers.HttpHeaders headers, string data)
{
- if (data == null) throw new ArgumentNullException(nameof(data));
- if (data.Length == 0) throw new ArgumentException("data cannot be an empty string.", nameof(data));
- if (!LineTerminators.Any(data.Contains)) throw new ArgumentException("data is not a valid request, it does not contain any CRLF/LF terminators.", nameof(data));
+ if (data == null)
+ {
+ throw new ArgumentNullException(nameof(data));
+ }
+
+ if (data.Length == 0)
+ {
+ throw new ArgumentException("data cannot be an empty string.", nameof(data));
+ }
+
+ if (!LineTerminators.Any(data.Contains))
+ {
+ throw new ArgumentException("data is not a valid request, it does not contain any CRLF/LF terminators.", nameof(data));
+ }
using (var retVal = new ByteArrayContent(Array.Empty<byte>()))
{
var lines = data.Split(LineTerminators, StringSplitOptions.None);
- //First line is the 'request' line containing http protocol details like method, uri, http version etc.
+ // First line is the 'request' line containing http protocol details like method, uri, http version etc.
ParseStatusLine(lines[0], message);
ParseHeaders(headers, retVal.Headers, lines);
@@ -73,18 +77,20 @@ namespace Rssdp.Infrastructure
/// <returns>A <see cref="Version"/> object containing the parsed version data.</returns>
protected Version ParseHttpVersion(string versionData)
{
- if (versionData == null) throw new ArgumentNullException(nameof(versionData));
+ if (versionData == null)
+ {
+ throw new ArgumentNullException(nameof(versionData));
+ }
var versionSeparatorIndex = versionData.IndexOf('/');
- if (versionSeparatorIndex <= 0 || versionSeparatorIndex == versionData.Length) throw new ArgumentException("request header line is invalid. Http Version not supplied or incorrect format.", nameof(versionData));
+ if (versionSeparatorIndex <= 0 || versionSeparatorIndex == versionData.Length)
+ {
+ throw new ArgumentException("request header line is invalid. Http Version not supplied or incorrect format.", nameof(versionData));
+ }
return Version.Parse(versionData.Substring(versionSeparatorIndex + 1));
}
- #endregion
-
- #region Private Methods
-
/// <summary>
/// Parses a line from an HTTP request or response message containing a header name and value pair.
/// </summary>
@@ -93,35 +99,39 @@ namespace Rssdp.Infrastructure
/// <param name="contentHeaders">A reference to a <see cref="System.Net.Http.Headers.HttpHeaders"/> collection for the message content, to which the parsed header will be added.</param>
private void ParseHeader(string line, System.Net.Http.Headers.HttpHeaders headers, System.Net.Http.Headers.HttpHeaders contentHeaders)
{
- //Header format is
- //name: value
+ // Header format is
+ // name: value
var headerKeySeparatorIndex = line.IndexOf(":", StringComparison.OrdinalIgnoreCase);
var headerName = line.Substring(0, headerKeySeparatorIndex).Trim();
var headerValue = line.Substring(headerKeySeparatorIndex + 1).Trim();
- //Not sure how to determine where request headers and and content headers begin,
- //at least not without a known set of headers (general headers first the content headers)
- //which seems like a bad way of doing it. So we'll assume if it's a known content header put it there
- //else use request headers.
+ // Not sure how to determine where request headers and and content headers begin,
+ // at least not without a known set of headers (general headers first the content headers)
+ // which seems like a bad way of doing it. So we'll assume if it's a known content header put it there
+ // else use request headers.
var values = ParseValues(headerValue);
var headersToAddTo = IsContentHeader(headerName) ? contentHeaders : headers;
if (values.Count > 1)
+ {
headersToAddTo.TryAddWithoutValidation(headerName, values);
+ }
else
+ {
headersToAddTo.TryAddWithoutValidation(headerName, values.First());
+ }
}
private int ParseHeaders(System.Net.Http.Headers.HttpHeaders headers, System.Net.Http.Headers.HttpHeaders contentHeaders, string[] lines)
{
- //Blank line separates headers from content, so read headers until we find blank line.
+ // Blank line separates headers from content, so read headers until we find blank line.
int lineIndex = 1;
string line = null, nextLine = null;
while (lineIndex + 1 < lines.Length && !String.IsNullOrEmpty((line = lines[lineIndex++])))
{
- //If the following line starts with space or tab (or any whitespace), it is really part of this header but split for human readability.
- //Combine these lines into a single comma separated style header for easier parsing.
+ // If the following line starts with space or tab (or any whitespace), it is really part of this header but split for human readability.
+ // Combine these lines into a single comma separated style header for easier parsing.
while (lineIndex < lines.Length && !String.IsNullOrEmpty((nextLine = lines[lineIndex])))
{
if (nextLine.Length > 0 && Char.IsWhiteSpace(nextLine[0]))
@@ -130,11 +140,14 @@ namespace Rssdp.Infrastructure
lineIndex++;
}
else
+ {
break;
+ }
}
ParseHeader(line, headers, contentHeaders);
}
+
return lineIndex;
}
@@ -153,7 +166,9 @@ namespace Rssdp.Infrastructure
var indexOfSeparator = headerValue.IndexOfAny(SeparatorCharacters);
if (indexOfSeparator <= 0)
+ {
values.Add(headerValue);
+ }
else
{
var segments = headerValue.Split(SeparatorCharacters);
@@ -163,13 +178,17 @@ namespace Rssdp.Infrastructure
{
var segment = segments[segmentIndex];
if (segment.Trim().StartsWith("\"", StringComparison.OrdinalIgnoreCase))
+ {
segment = CombineQuotedSegments(segments, ref segmentIndex, segment);
+ }
values.Add(segment);
}
}
else
+ {
values.AddRange(segments);
+ }
}
return values;
@@ -192,17 +211,20 @@ namespace Rssdp.Infrastructure
}
if (index + 1 < segments.Length)
+ {
trimmedSegment += "," + segments[index + 1].TrimEnd();
+ }
}
segmentIndex = segments.Length;
if (trimmedSegment.StartsWith("\"", StringComparison.OrdinalIgnoreCase) && trimmedSegment.EndsWith("\"", StringComparison.OrdinalIgnoreCase))
+ {
return trimmedSegment.Substring(1, trimmedSegment.Length - 2);
+ }
else
+ {
return trimmedSegment;
+ }
}
-
- #endregion
-
}
}