30

Redbot reports that my webpage has invalid header:

The ETag header's syntax isn't valid.

My headers are set to:

ETag: 4ae413bd

Why is it invalid?

What is the syntax for an ETag?

Pacerier
  • 86,231
  • 106
  • 366
  • 634

4 Answers4

37

Try ETag: "4ae413bd". The value of an ETag must follow the ABNF form:

  entity-tag = [ weak ] opaque-tag
  weak       = "W/"
  opaque-tag = quoted-string

  quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> )
  qdtext         = <any TEXT except <">>
  quoted-pair    = "\" CHAR
  CHAR           = <any US-ASCII character (octets 0 - 127)>
  TEXT           = <any OCTET except CTLs, but including LWS>
  OCTET          = <any 8-bit sequence of data>
  LWS            = [CRLF] 1*( SP | HT )
  CTL            = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
  CRLF           = CR LF
  CR             = <US-ASCII CR, carriage return (13)>
  LF             = <US-ASCII LF, linefeed (10)>
  SP             = <US-ASCII SP, space (32)>
  HT             = <US-ASCII HT, horizontal-tab (9)>

, which is basically ([wW]/)?"([^"]|\\")*" in regular regex.

Note that both "\" and "/" are valid values for etags.

References: section-14.19, section-3.11, section-2.2.

Pacerier
  • 86,231
  • 106
  • 366
  • 634
  • Although HTTP 1.1 allows `"\"`, the draft of HTTP 1.1 bis does not. In 2007, the W3C considered this issue - see http://www.w3.org/Protocols/HTTP/1.1/rfc2616bis/issues/#i31 - and decided that the grammar was wrong. It was fixed in draft 04. You can see the edit at http://greenbytes.de/tech/webdav/draft-lafon-rfc2616bis-04.html#rfc.issue.i31-qdtext-bnf. So whenever HTTP 1.1 bis eventually ships (assuming that it does) `"\"` will no longer be valid, so you would be wise to avoid it, even though it's technically allowed today. – Ian Griffiths Jun 27 '13 at 13:43
  • @IanGriffiths, what's the estimated shipping date? – Pacerier Jun 28 '13 at 07:21
  • I think the plan is for it to be submitted as a proposed standard in September 2013. (The relevant working group's last call was supposed to close earlier this year, and I think that did go ahead as planned.) I don't think there's a plan for how long it takes for it to move from "proposed" to fully fledged - I believe that depends on things that only become apparent later (e.g., rate of adoption, whether problems are found). – Ian Griffiths Jun 28 '13 at 11:53
  • 4
    In layman's terms: the value MUST begin and end with " (double quotes) – Arnaud Meuret Aug 29 '14 at 13:48
  • Updated version of RFC https://tools.ietf.org/html/rfc7232#section-2.3. It doesn't allow to use spaces e.g. – Nikolay Aug 17 '16 at 12:01
  • Technically, the 'W/' in the weak ETag is case-sensitive, so the regex should be `(W/)?"([^"]|\\")*"` – roryhewitt Oct 23 '20 at 18:33
  • the ETag can also be a * (without quotes) – M. Koch Feb 15 '22 at 16:03
15

As Arnaud mentioned, make sure that you have quoted the value.

replace

new EntityTagHeaderValue("0");

with

new EntityTagHeaderValue("\"0\"");
Martin Konecny
  • 57,827
  • 19
  • 139
  • 159
7

"An ETag is an opaque identifier assigned by a web server to a specific version of a resource found at a URL". This means it can be pretty much anything.

The problem is probably the syntax, use:

ETag: "4ae413bd"
Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
2

If you got here because of the stack trace below, make sure you uncheck the "Enable Browser Link" option in Visual Studio that causes this error : uncheck this

Conversion> [13:31:10 ERR] Connection id "0HLJ153E20LDJ", Request id "0HLJ153E20LDJ:00000003": An unhandled exception was thrown by the application.
Conversion> System.ObjectDisposedException: The response has been aborted due to an unhandled application exception. ---> System.FormatException: Invalid ETag name
Conversion>    at Microsoft.Net.Http.Headers.EntityTagHeaderValue..ctor(StringSegment tag, Boolean isWeak)
Conversion>    at Microsoft.Net.Http.Headers.EntityTagHeaderValue..ctor(StringSegment tag)
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.BrowserLinkMiddleWareUtil.AddToETag(ResponseHeaders responseHeader, Int32 port)
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.BrowserLinkMiddleware.<>c__DisplayClass7_0.<ExecuteWithFilter>b__0()
Conversion>    at Microsoft.AspNetCore.Http.HttpResponse.<>c.<.cctor>b__30_0(Object callback)
Conversion>    at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.FireOnStartingMayAwait(Stack`1 onStarting)
Conversion>    --- End of inner exception stack trace ---
Conversion>    at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ThrowResponseAbortedException()
Conversion>    at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.InitializeResponseAsync(Int32 firstWriteByteCount)
Conversion>    at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.WriteAsync(ReadOnlyMemory`1 data, CancellationToken cancellationToken)
Conversion>    at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseStream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
Conversion>    at System.IO.Stream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count)
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.ScriptInjectionFilterStream.<>c__DisplayClass37_0.<<CreateResponseHandler>b__0>d.MoveNext()
Conversion> --- End of stack trace from previous location where exception was thrown ---
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.SocketReader.ReadBytesIntoResponseHandler(Int64 totalBytesToRead, ResponseHandler handler, CancellationToken cancellationToken)
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.HttpSocketAdapter.ResponseReader.ReadBytesIntoResponse(Int64 bytesToRead)
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.HttpSocketAdapter.ResponseReader.ReadChunkedContent()
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.HttpSocketAdapter.ResponseReader.ReadResponse()
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.DelayConnectingHttpSocketAdapter.Microsoft.VisualStudio.Web.BrowserLink.IHttpSocketAdapter.WaitForResponseComplete()
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.ScriptInjectionFilterStream.WaitForFilterComplete()
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.BrowserLinkMiddleware.ExecuteWithFilter(IHttpSocketAdapter injectScriptSocket, String requestId, HttpContext httpContext)
Conversion>    at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Conversion>    at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Conversion>    at Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.Invoke(HttpContext httpContext)
Conversion>    at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
DevNull
  • 131
  • 7
Max Alexander Hanna
  • 3,388
  • 1
  • 25
  • 35