malformed_host_override.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // +build !windows
  2. package hack
  3. import "net"
  4. // MalformedHostHeaderOverride is a wrapper to be able
  5. // to overcome the 400 Bad request coming from old docker
  6. // clients that send an invalid Host header.
  7. type MalformedHostHeaderOverride struct {
  8. net.Listener
  9. }
  10. // MalformedHostHeaderOverrideConn wraps the underlying unix
  11. // connection and keeps track of the first read from http.Server
  12. // which just reads the headers.
  13. type MalformedHostHeaderOverrideConn struct {
  14. net.Conn
  15. first bool
  16. }
  17. var closeConnHeader = []byte("\r\nConnection: close\r")
  18. // Read reads the first *read* request from http.Server to inspect
  19. // the Host header. If the Host starts with / then we're talking to
  20. // an old docker client which send an invalid Host header. To not
  21. // error out in http.Server we rewrite the first bytes of the request
  22. // to sanitize the Host header itself.
  23. // In case we're not dealing with old docker clients the data is just passed
  24. // to the server w/o modification.
  25. func (l *MalformedHostHeaderOverrideConn) Read(b []byte) (n int, err error) {
  26. // http.Server uses a 4k buffer
  27. if l.first && len(b) == 4096 {
  28. // This keeps track of the first read from http.Server which just reads
  29. // the headers
  30. l.first = false
  31. // The first read of the connection by http.Server is done limited to
  32. // DefaultMaxHeaderBytes (usually 1 << 20) + 4096.
  33. // Here we do the first read which gets us all the http headers to
  34. // be inspected and modified below.
  35. c, err := l.Conn.Read(b)
  36. if err != nil {
  37. return c, err
  38. }
  39. var (
  40. start, end int
  41. firstLineFeed = -1
  42. buf []byte
  43. )
  44. for i := 0; i <= c-1-7; i++ {
  45. if b[i] == '\n' && firstLineFeed == -1 {
  46. firstLineFeed = i
  47. }
  48. if b[i] != '\n' {
  49. continue
  50. }
  51. if b[i+1] == '\r' && b[i+2] == '\n' {
  52. return c, nil
  53. }
  54. if b[i+1] != 'H' {
  55. continue
  56. }
  57. if b[i+2] != 'o' {
  58. continue
  59. }
  60. if b[i+3] != 's' {
  61. continue
  62. }
  63. if b[i+4] != 't' {
  64. continue
  65. }
  66. if b[i+5] != ':' {
  67. continue
  68. }
  69. if b[i+6] != ' ' {
  70. continue
  71. }
  72. if b[i+7] != '/' {
  73. continue
  74. }
  75. // ensure clients other than the docker clients do not get this hack
  76. if i != firstLineFeed {
  77. return c, nil
  78. }
  79. start = i + 7
  80. // now find where the value ends
  81. for ii, bbb := range b[start:c] {
  82. if bbb == '\n' {
  83. end = start + ii
  84. break
  85. }
  86. }
  87. buf = make([]byte, 0, c+len(closeConnHeader)-(end-start))
  88. // strip the value of the host header and
  89. // inject `Connection: close` to ensure we don't reuse this connection
  90. buf = append(buf, b[:start]...)
  91. buf = append(buf, closeConnHeader...)
  92. buf = append(buf, b[end:c]...)
  93. copy(b, buf)
  94. break
  95. }
  96. if len(buf) == 0 {
  97. return c, nil
  98. }
  99. return len(buf), nil
  100. }
  101. return l.Conn.Read(b)
  102. }
  103. // Accept makes the listener accepts connections and wraps the connection
  104. // in a MalformedHostHeaderOverrideConn initilizing first to true.
  105. func (l *MalformedHostHeaderOverride) Accept() (net.Conn, error) {
  106. c, err := l.Listener.Accept()
  107. if err != nil {
  108. return c, err
  109. }
  110. return &MalformedHostHeaderOverrideConn{c, true}, nil
  111. }