From 32bf48c6d8f5d8cdb163dc366fa2f8335c7e39d2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 11 Mar 2009 12:45:53 -0700 Subject: [PATCH] document http R=r DELTA=84 (63 added, 4 deleted, 17 changed) OCL=25950 CL=26126 --- src/lib/http/request.go | 62 ++++++++++++++++++++++++++++++++++++----- src/lib/http/status.go | 3 +- src/lib/http/url.go | 36 ++++++++++++++++-------- 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/src/lib/http/request.go b/src/lib/http/request.go index 5d1fd67d72..a2720ff01b 100644 --- a/src/lib/http/request.go +++ b/src/lib/http/request.go @@ -4,6 +4,11 @@ // HTTP Request reading and parsing. +// The http package implements parsing of HTTP requests and URLs +// and provides an extensible HTTP server. +// +// In the future it should also implement parsing of HTTP replies +// and provide methods to fetch URLs via HTTP. package http import ( @@ -20,6 +25,7 @@ const ( maxHeaderLines = 1024; ) +// HTTP request parsing errors. var ( LineTooLong = os.NewError("http header line too long"); ValueTooLong = os.NewError("http header value too long"); @@ -29,29 +35,67 @@ var ( BadHTTPVersion = os.NewError("unsupported http version"); ) -// HTTP Request +// A Request represents a parsed HTTP request header. type Request struct { Method string; // GET, PUT,etc. - RawUrl string; - Url *URL; // URI after GET, PUT etc. + RawUrl string; // The raw URL given in the request. + Url *URL; // URL after GET, PUT etc. Proto string; // "HTTP/1.0" ProtoMajor int; // 1 ProtoMinor int; // 0 + // A header mapping request lines to their values. + // If the header says + // + // Accept-Language: en-us + // accept-encoding: gzip, deflate + // Connection: keep-alive + // + // then + // + // Header = map[string]string{ + // "Accept-Encoding": "en-us", + // "Accept-Language": "gzip, deflate", + // "Connection": "keep-alive" + // } + // + // HTTP defines that header names are case-insensitive. + // The request parser implements this by canonicalizing the + // name, making the first character and any characters + // following a hyphen uppercase and the rest lowercase. Header map[string] string; + // Whether to close the connection after replying to this request. Close bool; + + // The host on which the URL is sought. + // Per RFC 2616, this is either the value of the Host: header + // or the host name given in the URL itself. Host string; - Referer string; // referer [sic] + + // The referring URL, if sent in the request. + // + // Referer is misspelled as in the request itself, + // a mistake from the earliest days of HTTP. + // This value can also be fetched from the Header map + // as Header["Referer"]; the benefit of making it + // available as a structure field is that the compiler + // can diagnose programs that use the alternate + // (correct English) spelling req.Referrer but cannot + // diagnose programs that use Header["Referrer"]. + Referer string; + + // The User-Agent: header string, if sent in the request. UserAgent string; } +// ProtoAtLeast returns whether the HTTP protocol used +// in the request is at least major.minor. func (r *Request) ProtoAtLeast(major, minor int) bool { return r.ProtoMajor > major || r.ProtoMajor == major && r.ProtoMinor >= minor } - // Read a line of bytes (up to \n) from b. // Give up if the line exceeds maxLineLength. // The returned bytes are a pointer into storage in @@ -188,6 +232,11 @@ func parseHTTPVersion(vers string) (int, int, bool) { var cmap = make(map[string]string) +// CanonicalHeaderKey returns the canonical format of the +// HTTP header key s. The canonicalization converts the first +// letter and any letter following a hyphen to upper case; +// the rest are converted to lowercase. For example, the +// canonical key for "accept-encoding" is "Accept-Encoding". func CanonicalHeaderKey(s string) string { if t, ok := cmap[s]; ok { return t; @@ -216,8 +265,7 @@ func CanonicalHeaderKey(s string) string { return t; } - -// Read and parse a request from b. +// ReadRequest reads and parses a request from b. func ReadRequest(b *bufio.BufRead) (req *Request, err *os.Error) { req = new(Request); diff --git a/src/lib/http/status.go b/src/lib/http/status.go index 82a8b214c4..6d1c5ab28a 100644 --- a/src/lib/http/status.go +++ b/src/lib/http/status.go @@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// HTTP status codes. See RFC 2616. - package http +// HTTP status codes, defined in RFC 2616. const ( StatusContinue = 100; StatusSwitchingProtocols = 101; diff --git a/src/lib/http/url.go b/src/lib/http/url.go index f0a94d68bc..0b2e9783ad 100644 --- a/src/lib/http/url.go +++ b/src/lib/http/url.go @@ -12,6 +12,7 @@ import ( "strings" ) +// Errors introduced by ParseURL. var ( BadURL = os.NewError("bad url syntax") ) @@ -40,7 +41,10 @@ func unhex(c byte) byte { return 0 } -// Unescape %xx into hex. +// URLUnescape unescapes a URL-encoded string, +// converting %AB into the byte 0xAB. +// It returns a BadURL error if each % is not followed +// by two hexadecimal digits. func URLUnescape(s string) (string, *os.Error) { // Count %, check that they're well-formed. n := 0; @@ -76,16 +80,19 @@ func URLUnescape(s string) (string, *os.Error) { return string(t), nil; } +// A URL represents a parsed URL (technically, a URI reference). +// The general form represented is: +// scheme://[userinfo@]host/path[?query][#fragment] type URL struct { - Raw string; - Scheme string; - RawPath string; - Authority string; - Userinfo string; - Host string; - Path string; - Query string; - Fragment string; + Raw string; // the original string + Scheme string; // scheme + RawPath string; // //[userinfo@]host/path[?query][#fragment] + Authority string; // [userinfo@]host + Userinfo string; // userinfo + Host string; // host + Path string; // /path + Query string; // query + Fragment string; // fragment } // Maybe rawurl is of the form scheme:path. @@ -126,7 +133,12 @@ func split(s string, c byte, cutc bool) (string, string) { return s, "" } -// Parse rawurl into a URL structure. +// BUG(rsc): ParseURL should canonicalize the path, +// removing unnecessary . and .. elements. + +// ParseURL parses rawurl into a URL structure. +// The string rawurl is assumed not to have a #fragment suffix. +// (Web browsers strip #fragment before sending the URL to a web server.) func ParseURL(rawurl string) (url *URL, err *os.Error) { if rawurl == "" { return nil, BadURL @@ -171,7 +183,7 @@ func ParseURL(rawurl string) (url *URL, err *os.Error) { return url, nil } -// A URL reference is a URL with #frag potentially added. Parse it. +// ParseURLReference is like ParseURL but allows a trailing #fragment. func ParseURLReference(rawurlref string) (url *URL, err *os.Error) { // Cut off #frag. rawurl, frag := split(rawurlref, '#', true); -- 2.48.1