Skip to content

Instantly share code, notes, and snippets.

@thomaslevesque
Created February 23, 2017 00:56
Show Gist options
  • Save thomaslevesque/d8ee28be1cf383a3f8aaf39cee776f92 to your computer and use it in GitHub Desktop.
Save thomaslevesque/d8ee28be1cf383a3f8aaf39cee776f92 to your computer and use it in GitHub Desktop.
Parsing HTTP authentication challenge with Sprache
void Main()
{
ParseAndPrintChallenge(@"Bearer realm=""FooCorp"", error=invalid_token, error_description=""The access token has expired""");
}
void ParseAndPrintChallenge(string input)
{
var challenge = Grammar.Challenge.Parse(input);
Console.WriteLine($"Scheme: {challenge.Scheme}");
Console.WriteLine($"Parameters:");
foreach (var p in challenge.Parameters)
{
Console.WriteLine($"- {p.Name} = {p.Value}");
}
}
static class Grammar
{
private static readonly Parser<char> DoubleQuote = Parse.Char('"');
private static readonly Parser<char> EqualSign = Parse.Char('=');
private static readonly Parser<char> Backslash = Parse.Char('\\');
private static readonly Parser<char> Comma = Parse.Char(',');
private static readonly Parser<char> SeparatorChar =
Parse.Chars("()<>@,;:\\\"/[]?={} \t");
private static readonly Parser<char> ControlChar =
Parse.Char(Char.IsControl, "Control character");
private static readonly Parser<char> TokenChar =
Parse.AnyChar
.Except(SeparatorChar)
.Except(ControlChar);
private static readonly Parser<string> Token =
TokenChar.AtLeastOnce().Text();
private static readonly Parser<char> QdText =
Parse.AnyChar.Except(DoubleQuote);
private static readonly Parser<char> QuotedPair =
from _ in Backslash
from c in Parse.AnyChar
select c;
private static readonly Parser<string> QuotedString =
from open in DoubleQuote
from text in QuotedPair.Or(QdText).Many().Text()
from close in DoubleQuote
select text;
private static readonly Parser<string> ParameterValue =
Token.Or(QuotedString);
private static readonly Parser<Parameter> Parameter =
from name in Token
from _ in EqualSign
from value in ParameterValue
select new Parameter(name, value);
private static readonly Parser<char> ListDelimiter =
from leading in Parse.WhiteSpace.Many()
from c in Comma
from trailing in Parse.WhiteSpace.Or(Comma).Many()
select c;
private static readonly Parser<Parameter[]> Parameters =
from p in Parameter.DelimitedBy(ListDelimiter)
select p.ToArray();
public static readonly Parser<Challenge> Challenge =
from scheme in Token
from _ in Parse.WhiteSpace.AtLeastOnce()
from parameters in Parameters
select new Challenge(scheme, parameters);
}
class Parameter
{
public Parameter(string name, string value)
{
Name = name;
Value = value;
}
public string Name { get; }
public string Value { get; }
}
class Challenge
{
public Challenge(string scheme, Parameter[] parameters)
{
Scheme = scheme;
Parameters = parameters;
}
public string Scheme { get; }
public Parameter[] Parameters { get; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment