// 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 }
// 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 }
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") }
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) }
// 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 }
// 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 }
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 }
// 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 }
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 }
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) }