chicken-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Chicken-users] http egg and the Host request-header field


From: Drew Hess
Subject: [Chicken-users] http egg and the Host request-header field
Date: Sun, 22 Feb 2009 14:02:22 -0800
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.3 (darwin)

Hi,

The HTTP/1.1 spec states that in the Host request-header field, the
port designation is optional if the default port is used for the
request. Chicken Scheme's http egg always sends the port, but some
petulant web servers don't like that.

Here are a couple of examples. Each of the examples demonstrates
communication with a URL "shortening" service, ala TinyURL. The
request headers shown here in my examples are what the http egg sends
when you do something like this:

(http:send-request (http:make-request 'HEAD "http://grf.me/Xs3";))

In this first example, grf.me responds that the URL doesn't exist:

   % telnet grf.me 80
   Trying 209.67.188.9...
   Connected to grf.me.
   Escape character is '^]'.
   HEAD /Xs3 HTTP/1.0
   Host: grf.me:80
   Content-Length: 0

   HTTP/1.1 404 Not Found
   Cache-Control: private
   Content-Length: 5165
   Content-Type: text/html; charset=utf-8
   Server: Microsoft-IIS/7.0
   X-AspNet-Version: 2.0.50727
   X-Powered-By: ASP.NET
   Date: Sun, 22 Feb 2009 21:37:54 GMT
   Connection: close

   Connection closed by foreign host.

But when you send the Host header without the port, it works fine:

    % telnet grf.me 80
    Trying 209.67.188.9...
    Connected to grf.me.
    Escape character is '^]'.
    HEAD /Xs3 HTTP/1.0
    Host: grf.me 
    Content-Length: 0

    HTTP/1.1 301 Moved Permanently
    Cache-Control: private
    Content-Length: 0
    Location: http://inthegraph.com/grfme/index/Xs3
    Server: Microsoft-IIS/7.0
    X-AspNet-Version: 2.0.50727
    X-Powered-By: UrlRewriter.NET 2.0.0
    X-Powered-By: ASP.NET
    Date: Sun, 22 Feb 2009 21:40:42 GMT
    Connection: close

    Connection closed by foreign host.

The results are the same for GET requests, and for HTTP/1.1 requests.

In the second example, ping.fm responds with a redirect, but it
redirects to the same URL, which causes an infinite loop if you're
trying to follow redirections to the terminal URL:

       % telnet ping.fm 80
       Trying 69.44.44.70...
       Connected to ping.fm.
       Escape character is '^]'.
       HEAD /LqHrn HTTP/1.0
       Host: ping.fm:80
       Content-Length: 0

       HTTP/1.1 301 Moved Permanently
       Date: Sun, 22 Feb 2009 21:32:18 GMT
       Server: Apache
       Location: http://ping.fm/LqHrn
       Connection: close
       Content-Type: text/html; charset=iso-8859-1

       Connection closed by foreign host.

Here it is without the port:

     telnet ping.fm 80
     Trying 69.44.44.70...
     Connected to ping.fm.
     Escape character is '^]'.
     HEAD /LqHrn HTTP/1.0
     Host: ping.fm
     Content-Length: 0

     HTTP/1.1 301 Moved Permanently
     Date: Sun, 22 Feb 2009 21:42:06 GMT
     Server: Apache
     Location: http://www.technologyreview.com/computing/22194/
     Content-Type: text/html; charset=UTF-8

     ^C
     Connection closed by foreign host.

That gives the proper Location.

Because the http egg always applies the port to the Host header,
there's no workaround for these broken web apps. Attached is a patch
for http so that it elides the port when it's the default.

thanks!
d
diff -urN http/http-client.scm http-dhess/http-client.scm
--- http/http-client.scm        2009-02-06 12:16:19.000000000 -0800
+++ http-dhess/http-client.scm  2009-02-22 13:20:50.000000000 -0800
@@ -195,6 +195,10 @@
        (display (car fragments))
        (loop (cdr fragments) #t)))))
 
+(define (default-port? serv port)
+  (or (and (string=? serv "http") (= port 80))
+      (and (string=? serv "https") (= port 443))))
+
 (define (http:send-request req . more)
   (let-optionals more ([in #f]
                       [out #f] )
@@ -224,8 +228,11 @@
                                           (if (= port 80) "" (conc ":" port))
                                           path " " proto "\r\n"))
                    (set! result (string-append method " " path " " proto
-                                          "\r\nHost: " host ":"
-                                          (->string port) "\r\n")))
+                                          "\r\nHost: " host
+                                           (if (default-port? serv port)
+                                               ""
+                                               (conc ":" port))
+                                           "\r\n")))
              (for-each
               (lambda (a)
                 (set! result (sprintf "~A~A: ~A\r\n" result (car a) (cdr a)) ))

Attachment: pgpcsTCyyEEFi.pgp
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]