Beispiel #1
2
func buildTestRequest(method string, path string, body string, headers map[string][]string, cookies []*http.Cookie) *http.Request {
	host := "127.0.0.1"
	port := "80"
	rawurl := "http://" + host + ":" + port + path
	url_, _ := url.Parse(rawurl)

	proto := "HTTP/1.1"

	if headers == nil {
		headers = map[string][]string{}
	}

	headers["User-Agent"] = []string{"web.go test"}
	if method == "POST" {
		headers["Content-Length"] = []string{fmt.Sprintf("%d", len(body))}
		if headers["Content-Type"] == nil {
			headers["Content-Type"] = []string{"text/plain"}
		}
	}

	req := http.Request{Method: method,
		RawURL: rawurl,
		URL:    url_,
		Proto:  proto,
		Host:   host,
		Header: http.Header(headers),
		Body:   ioutil.NopCloser(bytes.NewBufferString(body)),
	}

	for _, cookie := range cookies {
		req.AddCookie(cookie)
	}
	return &req
}
Beispiel #2
0
// for hdrs, see 'http://wiki.basho.com/HTTP-Fetch-Object.html'
// NB: If no accept is set, we will choose multipart/mixed.
func GetMultiItem(c Client, bucket, key string, hdrs http.Header, parms http.Values, respch chan<- *http.Response, cc *http.ClientConn) (err os.Error) {
	req := getMultiItemRequest(c, bucket, key, hdrs, parms)
	err = dispatchRequest(cc, req, map[int]func(*http.Response) os.Error{
		-1:  debugFailf(os.Stdout, true, "GetMultiItem failed"),
		400: func(*http.Response) os.Error { return ErrBadRequest },
		404: func(*http.Response) os.Error { return ErrUnknownKey },
		406: func(*http.Response) os.Error { return ErrUnacceptable },
		503: func(*http.Response) os.Error { return ErrServiceUnavailable },
		200: func(resp *http.Response) (err os.Error) {
			// This doesn't actually happen unless someone else has resolved the item for us, but we'll
			// take it if it happens.
			respch <- resp
			return
		},
		300: func(resp *http.Response) (err os.Error) {
			mtype, mparms := mime.ParseMediaType(resp.Header.Get("Content-Type"))
			if mtype != "multipart/mixed" {
				return debugFailf(os.Stdout, true, "Server gave us a 300, but not a multipart/mixed message\t"+mtype)(resp)
			}
			if err == nil && mparms["boundary"] == "" {
				err = os.NewError("No boundry name found in content-type")
			}
			if err == nil {
				mpart := multipart.NewReader(io.LimitReader(resp.Body, resp.ContentLength), mparms["boundary"])
				var part *multipart.Part
				for part, err = mpart.NextPart(); err == nil; part, err = mpart.NextPart() {
					// if we don't swallow the reader now, the caller may not get their bits (multipart closes when we call NextPart()).
					buff := bytes.NewBuffer(nil)
					n, _ := buff.ReadFrom(part)

					rr := &http.Response{
						Body:          ioutil.NopCloser(buff),
						Header:        http.Header(part.Header),
						ContentLength: int64(n),
					}
					// Riak doesn't include a vclock in the sub-headers, and readers may want to use them.
					rr.Header.Set("X-Riak-Vclock", resp.Header.Get("X-Riak-Vclock"))
					respch <- rr
				}
				if err == os.EOF {
					err = nil
				}
			}
			return
		},
	})
	close(respch)

	return
}
Beispiel #3
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
}