Ejemplo n.º 1
0
Archivo: httpc.go Proyecto: kr/httpc.go
// Much like http.Get. If s is nil, uses DefaultSender.
func Get(s Sender, url string) (rs []*http.Response, err os.Error) {
	for redirect := 0; ; redirect++ {
		if redirect >= 10 {
			err = os.ErrorString("stopped after 10 redirects")
			break
		}

		var req http.Request
		req.RawURL = url
		req.Header = map[string]string{}
		r, err := Send(s, &req)
		if err != nil {
			break
		}
		rs = prepend(r, rs)
		if shouldRedirect(r.StatusCode) {
			r.Body.Close()
			if url = r.GetHeader("Location"); url == "" {
				err = os.ErrorString(fmt.Sprintf("%d response missing Location header", r.StatusCode))
				break
			}
			continue
		}

		return
	}

	err = &http.URLError{"Get", url, err}
	return
}
Ejemplo n.º 2
0
// sent a request off to twitter. Returns the response's body or an error.
func send(url, method string, form map[string][]string, client *Client, body string) (result string, err os.Error) {
	req := new(http.Request)
	req.Method = method
	req.RawURL = url
	req.Host = URLHost
	req.Referer = "none"
	req.UserAgent = HTTPUserAgent
	req.Form = form
	req.Header = map[string]string{
		"Connection":    "Keep Alive",
		"Authorization": getAuthHeader(client),
	}
	req.Body = strings.NewReader(body)
	req.URL, err = http.ParseURL(req.RawURL)
	if err != nil {
		return "", err
	}

	// send request
	resp := new(http.Response)
	resp, err = http.Send(req)
	if err != nil {
		return "", err
	}
	result = getResponseBody(resp)
	return result, nil
}
Ejemplo n.º 3
0
func YadisRequest(url_ string, method string) (resp *http.Response, err os.Error) {
	resp = nil

	var request = new(http.Request)
	var client = new(http.Client)
	var Header = make(http.Header)

	request.Method = method
	request.RawURL = url_

	request.URL, err = url.Parse(url_)
	if err != nil {
		return
	}

	// Common parameters
	request.Proto = "HTTP/1.0"
	request.ProtoMajor = 1
	request.ProtoMinor = 0
	request.ContentLength = 0
	request.Close = true

	Header.Add("Accept", "application/xrds+xml")
	request.Header = Header

	// Follow a maximum of 5 redirections
	for i := 0; i < 5; i++ {
		response, err := client.Do(request)

		if err != nil {
			return nil, err
		}
		if response.StatusCode == 301 || response.StatusCode == 302 || response.StatusCode == 303 || response.StatusCode == 307 {
			location := response.Header.Get("Location")
			request.RawURL = location
			request.URL, err = url.Parse(location)
			if err != nil {
				return
			}
		} else {
			return response, nil
		}
	}
	return nil, os.NewError("Too many redirections")
}
Ejemplo n.º 4
0
Archivo: httpc.go Proyecto: kr/httpc.go
func sendBody(s Sender, url, method, bodyType string, body io.Reader) (r *http.Response, err os.Error) {
	var req http.Request
	req.Method = method
	req.RawURL = url
	req.Body = nopCloser{body}
	req.Header = map[string]string{
		"Content-Type": bodyType,
	}
	req.TransferEncoding = []string{"chunked"}
	return Send(s, &req)
}
Ejemplo n.º 5
0
// This function is launched async as a go routine. It tries to send a message
// to a remote server and sends a bool to nextChannel to indicate whether this
// has succeeded or not. It is not allowed to run this function multiple times in parallel
// for the same FederationGateway.
func (self *FederationGateway) sendFromQueue(req *WaveletUpdateRequest) {
	// No HTTP connection open yet?
	if self.connection == nil {
		con, err := net.Dial("tcp", "", fmt.Sprintf("%v:%v", self.manifest.HostName, self.manifest.Port))
		if err != nil {
			// TODO: Good error handling
			log.Println("Failed connecting to ", self.manifest, err)
			self.nextChannel <- false
			return
		}
		self.connection = http.NewClientConn(con, nil)
	}

	// Build the HTTP request
	var hreq http.Request
	hreq.Host = self.manifest.Domain
	hreq.Header = make(map[string]string)
	hreq.RawURL = fmt.Sprintf("http://%v:%v/fed%v", self.manifest.HostName, self.manifest.Port, req.uri)
	hreq.Method = "PUT"
	hreq.Body = NewRequestBody(req.Data)
	hreq.ContentLength = int64(len(req.Data))
	hreq.Header["Content-Type"] = req.MimeType
	log.Println("Sending WaveletUpdate to remote server ", hreq.RawURL)

	// Send the HTTP request
	self.connection.Write(&hreq)
	// Read the HTTP response
	hres, err := self.connection.Read()
	if err != nil {
		log.Println("Error reading HTTP response from ", self.manifest, err)
		// TODO: Better error handling
		self.connection.Close()
		self.connection = nil
		self.nextChannel <- false
		return
	}

	log.Println("After sending WaveletUpdate, status code is ", hres.StatusCode)
	// Success in sending the wavelet update?
	if hres.StatusCode == 200 {
		self.nextChannel <- true
		return
	}
	// Sending the wavelet update failed
	self.nextChannel <- false
}
Ejemplo n.º 6
0
// Modifies the request for signing
// if expiresIn is set to 0, a Timestamp will be used, otherwise an expiration.
func (p *signer) SignRequest(req *http.Request, expiresIn int64) {
	qstring, err := url.ParseQuery(req.URL.RawQuery)
	if err != nil {
		return
	}
	qstring["SignatureVersion"] = []string{DEFAULT_SIGNATURE_VERSION}
	if _, ok := qstring["SignatureMethod"]; !ok || len(qstring["SignatureMethod"]) == 0 {
		qstring["SignatureMethod"] = []string{DEFAULT_SIGNATURE_METHOD}
	}
	if expiresIn > 0 {
		qstring["Expires"] = []string{strconv.Itoa64(time.Seconds() + expiresIn)}
	} else {
		qstring["Timestamp"] = []string{time.UTC().Format(dm.UTC_DATETIME_FORMAT)}
	}
	qstring["Signature"] = nil, false
	qstring["DSOCAccessKeyId"] = []string{p.accessKey}

	var signature []byte
	req.URL.RawQuery = qstring.Encode()
	canonicalizedStringToSign, err := p.Canonicalize(req)
	if err != nil {
		return
	}
	//log.Printf("String-to-sign: '%s'", canonicalizedStringToSign)

	switch qstring["SignatureMethod"][0] {
	case SIGNATURE_METHOD_HMAC_SHA256:
		signature, err = p.SignEncoded(crypto.SHA256, canonicalizedStringToSign, base64.StdEncoding)
	case SIGNATURE_METHOD_HMAC_SHA1:
		signature, err = p.SignEncoded(crypto.SHA1, canonicalizedStringToSign, base64.StdEncoding)
	default:
		err = os.NewError("Unknown SignatureMethod:" + req.Form.Get("SignatureMethod"))
	}

	if err == nil {
		req.URL.RawQuery += "&" + url.Values{"Signature": []string{string(signature)}}.Encode()
		req.RawURL = req.URL.String()
	}
	return
}
Ejemplo n.º 7
0
func GetManifest(host string, port uint16) *ServerManifest {
	log.Println("Discovery at ", host, port)
	// Make a TCP connection
	con, err := net.Dial("tcp", "", fmt.Sprintf("%v:%v", host, port))
	if err != nil {
		log.Println("Failed connecting to ", host, port, err)
		return nil
	}
	// Make a HTTP connection
	hcon := http.NewClientConn(con, nil)
	// Build the HTTP request
	var hreq http.Request
	hreq.Host = host
	hreq.Method = "GET"
	hreq.RawURL = fmt.Sprintf("http://%v:%v/_manifest", host, port)
	log.Println("Sending request")
	// Send the HTTP request
	if err = hcon.Write(&hreq); err != nil {
		log.Println("Error sending GET request")
		hcon.Close()
		return nil
	}
	// Read the HTTP response
	_, err = hcon.Read()
	if err != nil {
		log.Println("Error reading HTTP response from ", host, err)
		hcon.Close()
		return nil
	}

	m := &ServerManifest{}
	// TODO: Parse the manifest
	// HACK START
	m.HostName = host
	m.Port = port
	// HACK END
	return m
}
Ejemplo n.º 8
0
// RequestFromMap creates an http.Request from CGI variables.
// The returned Request's Body field is not populated.
func RequestFromMap(params map[string]string) (*http.Request, os.Error) {
	r := new(http.Request)
	r.Method = params["REQUEST_METHOD"]
	if r.Method == "" {
		return nil, os.NewError("cgi: no REQUEST_METHOD in environment")
	}

	r.Proto = params["SERVER_PROTOCOL"]
	var ok bool
	r.ProtoMajor, r.ProtoMinor, ok = http.ParseHTTPVersion(r.Proto)
	if !ok {
		return nil, os.NewError("cgi: invalid SERVER_PROTOCOL version")
	}

	r.Close = true
	r.Trailer = http.Header{}
	r.Header = http.Header{}

	r.Host = params["HTTP_HOST"]
	r.Referer = params["HTTP_REFERER"]
	r.UserAgent = params["HTTP_USER_AGENT"]

	if lenstr := params["CONTENT_LENGTH"]; lenstr != "" {
		clen, err := strconv.Atoi64(lenstr)
		if err != nil {
			return nil, os.NewError("cgi: bad CONTENT_LENGTH in environment: " + lenstr)
		}
		r.ContentLength = clen
	}

	if ct := params["CONTENT_TYPE"]; ct != "" {
		r.Header.Set("Content-Type", ct)
	}

	// Copy "HTTP_FOO_BAR" variables to "Foo-Bar" Headers
	for k, v := range params {
		if !strings.HasPrefix(k, "HTTP_") || skipHeader[k] {
			continue
		}
		r.Header.Add(strings.Replace(k[5:], "_", "-", -1), v)
	}

	// TODO: cookies.  parsing them isn't exported, though.

	if r.Host != "" {
		// Hostname is provided, so we can reasonably construct a URL,
		// even if we have to assume 'http' for the scheme.
		r.RawURL = "http://" + r.Host + params["REQUEST_URI"]
		url, err := http.ParseURL(r.RawURL)
		if err != nil {
			return nil, os.NewError("cgi: failed to parse host and REQUEST_URI into a URL: " + r.RawURL)
		}
		r.URL = url
	}
	// Fallback logic if we don't have a Host header or the URL
	// failed to parse
	if r.URL == nil {
		r.RawURL = params["REQUEST_URI"]
		url, err := http.ParseURL(r.RawURL)
		if err != nil {
			return nil, os.NewError("cgi: failed to parse REQUEST_URI into a URL: " + r.RawURL)
		}
		r.URL = url
	}

	// There's apparently a de-facto standard for this.
	// http://docstore.mik.ua/orelly/linux/cgi/ch03_02.htm#ch03-35636
	if s := params["HTTPS"]; s == "on" || s == "ON" || s == "1" {
		r.TLS = &tls.ConnectionState{HandshakeComplete: true}
	}

	// Request.RemoteAddr has its port set by Go's standard http
	// server, so we do here too. We don't have one, though, so we
	// use a dummy one.
	r.RemoteAddr = net.JoinHostPort(params["REMOTE_ADDR"], "0")

	return r, nil
}
Ejemplo n.º 9
0
func requestFromEnvironment(env map[string]string) (*http.Request, os.Error) {
	r := new(http.Request)
	r.Method = env["REQUEST_METHOD"]
	if r.Method == "" {
		return nil, os.NewError("cgi: no REQUEST_METHOD in environment")
	}
	r.Close = true
	r.Trailer = http.Header{}
	r.Header = http.Header{}

	r.Host = env["HTTP_HOST"]
	r.Referer = env["HTTP_REFERER"]
	r.UserAgent = env["HTTP_USER_AGENT"]

	// CGI doesn't allow chunked requests, so these should all be accurate:
	r.Proto = "HTTP/1.0"
	r.ProtoMajor = 1
	r.ProtoMinor = 0
	r.TransferEncoding = nil

	if lenstr := env["CONTENT_LENGTH"]; lenstr != "" {
		clen, err := strconv.Atoi64(lenstr)
		if err != nil {
			return nil, os.NewError("cgi: bad CONTENT_LENGTH in environment: " + lenstr)
		}
		r.ContentLength = clen
		r.Body = ioutil.NopCloser(io.LimitReader(os.Stdin, clen))
	}

	// Copy "HTTP_FOO_BAR" variables to "Foo-Bar" Headers
	for k, v := range env {
		if !strings.HasPrefix(k, "HTTP_") || skipHeader[k] {
			continue
		}
		r.Header.Add(strings.Replace(k[5:], "_", "-", -1), v)
	}

	// TODO: cookies.  parsing them isn't exported, though.

	if r.Host != "" {
		// Hostname is provided, so we can reasonably construct a URL,
		// even if we have to assume 'http' for the scheme.
		r.RawURL = "http://" + r.Host + env["REQUEST_URI"]
		url, err := http.ParseURL(r.RawURL)
		if err != nil {
			return nil, os.NewError("cgi: failed to parse host and REQUEST_URI into a URL: " + r.RawURL)
		}
		r.URL = url
	}
	// Fallback logic if we don't have a Host header or the URL
	// failed to parse
	if r.URL == nil {
		r.RawURL = env["REQUEST_URI"]
		url, err := http.ParseURL(r.RawURL)
		if err != nil {
			return nil, os.NewError("cgi: failed to parse REQUEST_URI into a URL: " + r.RawURL)
		}
		r.URL = url
	}
	return r, nil
}
Ejemplo n.º 10
0
func (self *FederationProxy) sendFromQueue() {
	if len(self.queue) == 0 {
		return
	}

	log.Println("Sending message from queue")

	// No HTTP connection open yet?
	if self.connection == nil {
		con, err := net.Dial("tcp", "", fmt.Sprintf("%v:%v", self.manifest.HostName, self.manifest.Port))
		if err != nil {
			// TODO: Good error handling
			log.Println("Failed connecting to ", self.manifest, err)
			return
		}
		self.connection = http.NewClientConn(con, nil)
	}

	// Dequeue a message
	req := self.queue.At(0).(FederationRequest)
	// Build the HTTP request
	var hreq http.Request
	hreq.Host = self.manifest.Domain
	hreq.Header = make(map[string]string)
	switch req.(type) {
	case *PostRequest:
		preq := req.(*PostRequest)
		hreq.RawURL = fmt.Sprintf("http://%v:%v/fed/%v", self.manifest.HostName, self.manifest.Port, preq.URI.String())
		hreq.Method = "POST"
		hreq.Body = NewRequestBody(preq.Data)
		hreq.ContentLength = int64(len(preq.Data))
		hreq.Header["Content-Type"] = preq.MimeType
	case *GetRequest:
		greq := req.(*GetRequest)
		hreq.Method = "GET"
		hreq.RawURL = fmt.Sprintf("http://%v:%v/fed/%v", self.manifest.HostName, self.manifest.Port, greq.URI.String())
	default:
		log.Println(req)
		panic("Unsupported kind of message forwarded internally to the federation proxy")
	}
	log.Println("Sending request to ", hreq.RawURL)

	// Send the HTTP request
	self.connection.Write(&hreq)
	// Read the HTTP response
	hres, err := self.connection.Read()
	if err != nil {
		log.Println("Error reading HTTP response from ", self.manifest, err)
		// TODO: Better error handling
		self.connection.Close()
		self.connection = nil
		return
	}

	// Success. Remove the request from the queue
	self.queue.Delete(0)

	// Send the result back to the client
	_, err = io.Copy(req.GetResponseWriter(), hres.Body)
	hres.Body.Close()
	if err != nil {
		log.Println("Error sending result of federated message back to the client")
		req.SendFinishSignal(false)
	}
	req.SendFinishSignal(true)
}