Remove regex usage from std.net.curl

This commit is contained in:
Dennis Korpel 2023-12-24 17:51:05 +01:00
parent f41348cda4
commit 096dee19e0

View file

@ -2419,8 +2419,8 @@ struct HTTP
@system @property void onReceiveHeader(void delegate(in char[] key, @system @property void onReceiveHeader(void delegate(in char[] key,
in char[] value) callback) in char[] value) callback)
{ {
import std.algorithm.searching : startsWith; import std.algorithm.searching : findSplit, startsWith;
import std.regex : regex, match; import std.string : indexOf, chomp;
import std.uni : toLower; import std.uni : toLower;
// Wrap incoming callback in order to separate http status line from // Wrap incoming callback in order to separate http status line from
@ -2447,21 +2447,18 @@ struct HTTP
return; return;
} }
// Normal http header auto m = header.findSplit(": ");
auto m = match(cast(char[]) header, regex("(.*?): (.*)$")); auto fieldName = m[0].toLower();
auto fieldContent = m[2].chomp;
auto fieldName = m.captures[1].toLower().idup;
if (fieldName == "content-type") if (fieldName == "content-type")
{ {
auto mct = match(cast(char[]) m.captures[2], auto io = indexOf(fieldContent, "charset=", No.caseSensitive);
regex("charset=([^;]*)", "i")); if (io != -1)
if (!mct.empty && mct.captures.length > 1) charset = fieldContent[io + "charset=".length .. $].findSplit(";")[0].idup;
charset = mct.captures[1].idup;
} }
if (!m[1].empty && callback !is null)
if (!m.empty && callback !is null) callback(fieldName, fieldContent);
callback(fieldName, m.captures[2]); headersIn[fieldName] = fieldContent.idup;
headersIn[fieldName] = m.captures[2].idup;
} }
catch (UTFException e) catch (UTFException e)
{ {
@ -2479,20 +2476,27 @@ struct HTTP
/// Parse status line, as received from / generated by cURL. /// Parse status line, as received from / generated by cURL.
private static bool parseStatusLine(const char[] header, out StatusLine status) @safe private static bool parseStatusLine(const char[] header, out StatusLine status) @safe
{ {
import std.conv : to; import std.algorithm.searching : findSplit, startsWith;
import std.regex : regex, match; import std.conv : to, ConvException;
const m = match(header, regex(r"^HTTP/(\d+)(?:\.(\d+))? (\d+)(?: (.*))?$")); if (!header.startsWith("HTTP/"))
if (m.empty) return false;
return false; // Invalid status line
else try
{ {
status.majorVersion = to!ushort(m.captures[1]); const m = header["HTTP/".length .. $].findSplit(" ");
status.minorVersion = m.captures[2].length ? to!ushort(m.captures[2]) : 0; const v = m[0].findSplit(".");
status.code = to!ushort(m.captures[3]); status.majorVersion = to!ushort(v[0]);
status.reason = m.captures[4].idup; status.minorVersion = v[1].length ? to!ushort(v[2]) : 0;
const s2 = m[2].findSplit(" ");
status.code = to!ushort(s2[0]);
status.reason = s2[2].idup;
return true; return true;
} }
catch (ConvException e)
{
return false;
}
} }
@safe unittest @safe unittest
@ -2505,6 +2509,12 @@ struct HTTP
// The HTTP2 protocol is binary; cURL generates this fake text header. // The HTTP2 protocol is binary; cURL generates this fake text header.
assert(parseStatusLine("HTTP/2 200", status) assert(parseStatusLine("HTTP/2 200", status)
&& status == StatusLine(2, 0, 200, null)); && status == StatusLine(2, 0, 200, null));
assert(!parseStatusLine("HTTP/2", status));
assert(!parseStatusLine("HTTP/2 -1", status));
assert(!parseStatusLine("HTTP/2 200", status));
assert(!parseStatusLine("HTTP/2.X 200", status));
assert(!parseStatusLine("HTTP|2 200", status));
} }
/** Time condition enumeration as an alias of $(REF CurlTimeCond, etc,c,curl) /** Time condition enumeration as an alias of $(REF CurlTimeCond, etc,c,curl)