Esempio n. 1
0
// writeCookies writes the wire representation of the cookies
// to w. Each cookie is written on a separate "Cookie: " line.
// This choice is made because HTTP parsers tend to have a limit on
// line-length, so it seems safer to place cookies on separate lines.
func writeCookies(w io.Writer, kk []*http.Cookie) os.Error {
	lines := make([]string, 0, len(kk))
	var b bytes.Buffer
	for _, c := range kk {
		b.Reset()
		n := c.Name
		// TODO(petar): c.Value (below) should be unquoted if it is recognized as quoted
		fmt.Fprintf(&b, "%s=%s", http.CanonicalHeaderKey(n), c.Value)
		if len(c.Path) > 0 {
			fmt.Fprintf(&b, "; $Path=%s", http.URLEscape(c.Path))
		}
		if len(c.Domain) > 0 {
			fmt.Fprintf(&b, "; $Domain=%s", http.URLEscape(c.Domain))
		}
		if c.HttpOnly {
			fmt.Fprintf(&b, "; $HttpOnly")
		}
		lines = append(lines, "Cookie: "+b.String()+"\r\n")
	}
	sort.Strings(lines)
	for _, l := range lines {
		if _, err := io.WriteString(w, l); err != nil {
			return err
		}
	}
	return nil
}
Esempio n. 2
0
// matchMap returns true if the given key/value pairs exist in a given map.
func matchMap(toCheck map[string]string, toMatch map[string][]string,
	canonicalKey bool) bool {
	for k, v := range toCheck {
		// Check if key exists.
		if canonicalKey {
			k = http.CanonicalHeaderKey(k)
		}
		if values, keyExists := toMatch[k]; !keyExists {
			return false
		} else if v != "" {
			// If value was defined as an empty string we only check that the
			// key exists. Otherwise we also check if the value exists.
			valueExists := false
			for _, value := range values {
				if v == value {
					valueExists = true
					break
				}
			}
			if !valueExists {
				return false
			}
		}
	}
	return true
}
Esempio n. 3
0
// Internal. Parses headers in NNTP articles. Most of this is stolen from the http package,
// and it should probably be split out into a generic RFC822 header-parsing package.
func (c *Conn) readHeader(r *bufio.Reader) (res *Article, err os.Error) {
	res = new(Article)
	res.Header = make(map[string][]string)
	for {
		var key, value string
		if key, value, err = readKeyValue(r); err != nil {
			return nil, err
		}
		if key == "" {
			break
		}
		key = http.CanonicalHeaderKey(key)
		// RFC 3977 says nothing about duplicate keys' values being equivalent to
		// a single key joined with commas, so we keep all values seperate.
		oldvalue, present := res.Header[key]
		if present {
			sv := vector.StringVector(oldvalue)
			sv.Push(value)
			res.Header[key] = []string(sv)
		} else {
			res.Header[key] = []string{value}
		}
	}
	return res, nil
}
Esempio n. 4
0
File: httpc.go Progetto: kr/httpc.go
func Send(s Sender, req *http.Request) (resp *http.Response, err os.Error) {
	if s == nil {
		s = DefaultSender
	}
	req.ProtoMajor = 1
	req.ProtoMinor = 1
	header := req.Header
	req.Header = map[string]string{}
	for k, v := range header {
		req.Header[http.CanonicalHeaderKey(k)] = v
	}
	return s.Send(req)
}
Esempio n. 5
0
func newRequestCgi(headers http.Header, body io.Reader) *Request {
	var httpheader = make(http.Header)
	for header, value := range headers {
		if strings.HasPrefix(header, "Http_") {
			newHeader := header[5:]
			newHeader = strings.Replace(newHeader, "_", "-", -1)
			newHeader = http.CanonicalHeaderKey(newHeader)
			httpheader[newHeader] = value
		}
	}

	host := httpheader.Get("Host")
	method := headers.Get("REQUEST_METHOD")
	path := headers.Get("REQUEST_URI")
	port := headers.Get("SERVER_PORT")
	proto := headers.Get("SERVER_PROTOCOL")
	rawurl := "http://" + host + ":" + port + path
	url_, _ := url.Parse(rawurl)
	useragent := headers.Get("USER_AGENT")
	remoteAddr := headers.Get("REMOTE_ADDR")
	remotePort, _ := strconv.Atoi(headers.Get("REMOTE_PORT"))

	if method == "POST" {
		if ctype, ok := headers["CONTENT_TYPE"]; ok {
			httpheader["Content-Type"] = ctype
		}

		if clength, ok := headers["CONTENT_LENGTH"]; ok {
			httpheader["Content-Length"] = clength
		}
	}

	//read the cookies
	cookies := readCookies(httpheader)

	req := Request{
		Method:     method,
		RawURL:     rawurl,
		URL:        url_,
		Proto:      proto,
		Host:       host,
		UserAgent:  useragent,
		Body:       body,
		Headers:    httpheader,
		RemoteAddr: remoteAddr,
		RemotePort: remotePort,
		Cookie:     cookies,
	}

	return &req
}
Esempio n. 6
0
func newRequestCgi(headers map[string]string, body io.Reader) *Request {
	var httpheader = make(map[string]string)

	//copy HTTP_ variables
	for header, value := range headers {
		if strings.HasPrefix(header, "HTTP_") {
			newHeader := header[5:]
			newHeader = strings.Replace(newHeader, "_", "-", -1)
			newHeader = http.CanonicalHeaderKey(newHeader)
			httpheader[newHeader] = value
		}
	}

	host := httpheader["Host"]
	method, _ := headers["REQUEST_METHOD"]
	path, _ := headers["REQUEST_URI"]
	port, _ := headers["SERVER_PORT"]
	proto, _ := headers["SERVER_PROTOCOL"]
	rawurl := "http://" + host + ":" + port + path
	url, _ := http.ParseURL(rawurl)
	useragent, _ := headers["USER_AGENT"]
	remoteAddr, _ := headers["REMOTE_ADDR"]
	remotePort, _ := strconv.Atoi(headers["REMOTE_PORT"])

	if method == "POST" {
		if ctype, ok := headers["CONTENT_TYPE"]; ok {
			httpheader["Content-Type"] = ctype
		}

		if clength, ok := headers["CONTENT_LENGTH"]; ok {
			httpheader["Content-Length"] = clength
		}
	}

	req := Request{
		Method:     method,
		RawURL:     rawurl,
		URL:        url,
		Proto:      proto,
		Host:       host,
		UserAgent:  useragent,
		Body:       body,
		Headers:    httpheader,
		RemoteAddr: remoteAddr,
		RemotePort: remotePort,
	}

	return &req
}
Esempio n. 7
0
// writeSetCookies writes the wire representation of the set-cookies
// to w. Each cookie is written on a separate "Set-Cookie: " line.
// This choice is made because HTTP parsers tend to have a limit on
// line-length, so it seems safer to place cookies on separate lines.
func writeSetCookies(w io.Writer, kk []*http.Cookie) os.Error {
	if kk == nil {
		return nil
	}
	lines := make([]string, 0, len(kk))
	var b bytes.Buffer
	for _, c := range kk {
		b.Reset()
		// TODO(petar): c.Value (below) should be unquoted if it is recognized as quoted
		fmt.Fprintf(&b, "%s=%s", http.CanonicalHeaderKey(c.Name), c.Value)
		if len(c.Path) > 0 {
			fmt.Fprintf(&b, "; Path=%s", http.URLEscape(c.Path))
		}
		if len(c.Domain) > 0 {
			fmt.Fprintf(&b, "; Domain=%s", http.URLEscape(c.Domain))
		}
		if len(c.Expires.Zone) > 0 {
			fmt.Fprintf(&b, "; Expires=%s", c.Expires.Format(time.RFC1123))
		}
		if c.MaxAge >= 0 {
			fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
		}
		if c.HttpOnly {
			fmt.Fprintf(&b, "; HttpOnly")
		}
		if c.Secure {
			fmt.Fprintf(&b, "; Secure")
		}
		lines = append(lines, "Set-Cookie: "+b.String()+"\r\n")
	}
	sort.Strings(lines)
	for _, l := range lines {
		if _, err := io.WriteString(w, l); err != nil {
			return err
		}
	}
	return nil
}
Esempio n. 8
0
// RoundTrip issues a single HTTP request and returns its response. Per the
// http.RoundTripper interface, RoundTrip only returns an error if there
// was a problem with the request being malformed
// (ErrInvalidFetchRequest) or the URL Fetch proxy fails (ErrFetch).
// Note that HTTP response codes such as 5xx, 403, 404, etc are not
// errors as far as the transport is concerned and will be returned
// with err set to nil.
func (t *Transport) RoundTrip(req *http.Request) (res *http.Response, err os.Error) {
	methNum, ok := pb.URLFetchRequest_RequestMethod_value[req.Method]
	if !ok {
		return nil, &ErrInvalidFetchRequest{"Unsupported method: " + req.Method, nil}
	}

	method := pb.URLFetchRequest_RequestMethod(methNum)

	freq := &pb.URLFetchRequest{
		Method:                        &method,
		Url:                           proto.String(req.URL.String()),
		FollowRedirects:               proto.Bool(false), // http.Client's responsibility
		MustValidateServerCertificate: proto.Bool(!t.AllowInvalidServerCertificate),
	}

	if t.DeadlineSeconds != 0 {
		freq.Deadline = proto.Float64(t.DeadlineSeconds)
	}

	for k, vals := range req.Header {
		for _, val := range vals {
			freq.Header = append(freq.Header, &pb.URLFetchRequest_Header{
				Key:   proto.String(k),
				Value: proto.String(val),
			})
		}
	}
	if methodAcceptsRequestBody[req.Method] {
		freq.Payload, err = ioutil.ReadAll(req.Body)
		if err != nil {
			return nil, &ErrInvalidFetchRequest{"Failed to read body", err}
		}
	}

	fres := &pb.URLFetchResponse{}
	if err := t.Context.Call("urlfetch", "Fetch", freq, fres); err != nil {
		return nil, &ErrFetch{err.String()}
	}

	res = &http.Response{}
	res.StatusCode = int(*fres.StatusCode)
	res.Status = fmt.Sprintf("%d %s", res.StatusCode, statusCodeToText(res.StatusCode))
	res.Header = http.Header(make(map[string][]string))
	res.RequestMethod = req.Method

	// Faked:
	res.ProtoMajor = 1
	res.ProtoMinor = 1
	res.Proto = "HTTP/1.1"
	res.Close = true

	for _, h := range fres.Header {
		hkey := http.CanonicalHeaderKey(*h.Key)
		hval := *h.Value
		if hkey == "Content-Length" {
			// Will get filled in below for all but HEAD requests.
			if req.Method == "HEAD" {
				res.ContentLength, _ = strconv.Atoi64(hval)
			}
			continue
		}
		res.Header.Add(hkey, hval)
	}

	if req.Method != "HEAD" {
		res.ContentLength = int64(len(fres.Content))
	}

	truncated := proto.GetBool(fres.ContentWasTruncated)
	res.Body = &bodyReader{content: fres.Content, truncated: truncated}
	return
}
Esempio n. 9
0
File: httpc.go Progetto: kr/httpc.go
func getHeader(r *http.Request, key string) (value string) {
	return r.Header[http.CanonicalHeaderKey(key)]
}
Esempio n. 10
0
func (r *response) SetHeader(hdr, val string) {
	r.header[http.CanonicalHeaderKey(hdr)] = val
}