func (conn *streamConn) connect() (*http.Response, os.Error) { if conn.stale { return nil, os.NewError("Stale connection") } tcpConn, err := net.Dial("tcp", "", conn.url.Host+":80") if err != nil { return nil, err } conn.clientConn = http.NewClientConn(tcpConn, nil) var req http.Request req.URL = conn.url req.Method = "GET" req.Header = map[string]string{} req.Header["Authorization"] = "Basic " + conn.authData if conn.postData != "" { req.Method = "POST" req.Body = nopCloser{bytes.NewBufferString(conn.postData)} req.ContentLength = int64(len(conn.postData)) req.Header["Content-Type"] = "application/x-www-form-urlencoded" } err = conn.clientConn.Write(&req) if err != nil { return nil, err } resp, err := conn.clientConn.Read() if err != nil { return nil, err } return resp, nil }
// 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 }
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 nmcPOST(body *bytes.Buffer) (response *http.Response, err os.Error) { client := http.Client{} var req http.Request req.Method = "POST" req.ProtoMajor = 1 req.ProtoMinor = 1 req.Close = true req.Body = ioutil.NopCloser(body) req.Header = http.Header{ "Content-Type": []string{"text/plain"}, "Content-Length": []string{strconv.Itoa(body.Len())}, } req.ContentLength = int64(body.Len()) req.URL = options.nmcURL return client.Do(&req) }
func (conn *streamConn) connect() (*http.Response, os.Error) { if conn.stale { return nil, os.NewError("Stale connection") } var tcpConn net.Conn var err os.Error if proxy := os.Getenv("HTTP_PROXY"); len(proxy) > 0 { proxy_url, _ := url.Parse(proxy) tcpConn, err = net.Dial("tcp", proxy_url.Host) } else { tcpConn, err = net.Dial("tcp", conn.url.Host+":443") } if err != nil { return nil, err } cf := &tls.Config{Rand: rand.Reader, Time: time.Nanoseconds} ssl := tls.Client(tcpConn, cf) conn.clientConn = http.NewClientConn(ssl, nil) var req http.Request req.URL = conn.url req.Method = "GET" req.Header = http.Header{} req.Header.Set("Authorization", "Basic "+conn.authData) if conn.postData != "" { req.Method = "POST" req.Body = nopCloser{bytes.NewBufferString(conn.postData)} req.ContentLength = int64(len(conn.postData)) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") } resp, err := conn.clientConn.Do(&req) if err != nil { return nil, err } return resp, nil }
// PostForm issues a POST to the specified URL, // with data's keys and values urlencoded as the request body. // // Caller should close r.Body when done reading from it. func Post(t *Test) (r *http.Response, finalUrl string, cookies []*http.Cookie, err os.Error) { var req http.Request var url = t.Url req.Method = "POST" req.ProtoMajor = 1 req.ProtoMinor = 1 req.Close = true var body *bytes.Buffer var contentType string if hasFile(&t.Param) || t.Method == "POST:mp" { var boundary string body, boundary = multipartBody(&t.Param) contentType = "multipart/form-data; boundary=" + boundary } else { contentType = "application/x-www-form-urlencoded" bodystr := http.EncodeQuery(t.Param) body = bytes.NewBuffer([]byte(bodystr)) } req.Body = nopCloser{body} req.Header = http.Header{ "Content-Type": {contentType}, "Content-Length": {strconv.Itoa(body.Len())}, } addHeadersAndCookies(&req, t) req.ContentLength = int64(body.Len()) req.URL, err = http.ParseURL(url) if err != nil { return nil, url, cookies, err } debug("Will post to %s", req.URL.String()) r, finalUrl, cookies, err = DoAndFollow(&req, t.Dump) return }
// 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 (p *Propolis) SendRequest(method string, reduced bool, src string, target *url.URL, body io.ReadCloser, hash string, info *os.FileInfo) (resp *http.Response, err os.Error) { defer func() { // if anything goes wrong, close the body reader // if it ends normally, this will be closed already and set to nil if body != nil { body.Close() } }() var req *http.Request if req, err = http.NewRequest(method, target.String(), body); err != nil { return } // set upload file info if applicable if info != nil && body != nil { // TODO: 0-length files fail because the Content-Length field is missing // a fix is in the works in the Go library req.ContentLength = info.Size } if info != nil { p.SetRequestMetaData(req, info) } // reduced redundancy? if reduced { req.Header.Set("X-Amz-Storage-Class", "REDUCED_REDUNDANCY") } // are we uploading a file with a content hash? if hash != "" { req.Header.Set("Content-MD5", hash) } // is this a copy/metadata update? if src != "" { // note: src should already be a full bucket + path name u := new(url.URL) u.Path = src req.Header.Set("X-Amz-Copy-Source", u.String()) req.Header.Set("X-Amz-Metadata-Directive", "REPLACE") } // sign and execute the request // note: 2nd argument is temporary hack to set Content-Length: 0 when needed if resp, err = p.SignAndExecute(req, method == "PUT" && body == nil || (info != nil && info.Size == 0)); err != nil { return } // body was closed when the request was written out, // so nullify the deferred close body = nil if resp.StatusCode < 200 || resp.StatusCode > 299 { err = os.NewError(resp.Status) return } return }
func (s Session) perform(method, url, data string) { var req http.Request req.URL, _ = http.ParseURL(url) req.Method = method req.Header = s.headers req.ContentLength = int64(len(data)) req.Body = myCloser{bytes.NewBufferString(data)} if *verbose { req.Write(os.Stderr) } retry := 0 request: req.Body = myCloser{bytes.NewBufferString(data)} // recreate anew, in case of retry err := s.conn.Write(&req) if err != nil { if retry < 2 { if err == io.ErrUnexpectedEOF { // the underlying connection has been closed "gracefully" retry++ s.conn.Close() s.conn = dial(s.host) goto request } else if protoerr, ok := err.(*http.ProtocolError); ok && protoerr == http.ErrPersistEOF { // the connection has been closed in an HTTP keepalive sense retry++ s.conn.Close() s.conn = dial(s.host) goto request } } fmt.Fprintln(os.Stderr, "http-gonsole: could not send request:", err) os.Exit(1) } r, err := s.conn.Read(&req) if err != nil { if protoerr, ok := err.(*http.ProtocolError); ok && protoerr == http.ErrPersistEOF { // the remote requested that this be the last request serviced, // we proceed as the response is still valid defer s.conn.Close() defer func() { s.conn = dial(s.host) }() goto output } fmt.Fprintln(os.Stderr, "http-gonsole: could not read response:", err) os.Exit(1) } output: if len(data) > 0 { fmt.Println() } if r.StatusCode >= 500 { fmt.Printf(colorize(C_5xx, "%s %s\n"), r.Proto, r.Status) } else if r.StatusCode >= 400 { fmt.Printf(colorize(C_4xx, "%s %s\n"), r.Proto, r.Status) } else if r.StatusCode >= 300 { fmt.Printf(colorize(C_3xx, "%s %s\n"), r.Proto, r.Status) } else if r.StatusCode >= 200 { fmt.Printf(colorize(C_2xx, "%s %s\n"), r.Proto, r.Status) } if len(r.Header) > 0 { for key, arr := range r.Header { for _, val := range arr { fmt.Printf(colorize(C_Header, "%s: "), key) fmt.Println(val) } } fmt.Println() } if *rememberCookies { if cookies, found := r.Header["Set-Cookie"]; found { for _, h := range cookies { cookie := new(Cookie) cookie.Items = map[string]string{} re, _ := regexp.Compile("^[^=]+=[^;]+(; *(expires=[^;]+|path=[^;,]+|domain=[^;,]+|secure))*,?") rs := re.FindAllString(h, -1) for _, ss := range rs { m := strings.Split(ss, ";", -1) for _, n := range m { t := strings.Split(n, "=", 2) if len(t) == 2 { t[0] = strings.Trim(t[0], " ") t[1] = strings.Trim(t[1], " ") switch t[0] { case "domain": cookie.domain = t[1] case "path": cookie.path = t[1] case "expires": tm, err := time.Parse("Fri, 02-Jan-2006 15:04:05 MST", t[1]) if err != nil { tm, err = time.Parse("Fri, 02-Jan-2006 15:04:05 -0700", t[1]) } cookie.expires = tm case "secure": cookie.secure = true case "HttpOnly": cookie.httpOnly = true default: cookie.Items[t[0]] = t[1] } } } } *s.cookies = append(*s.cookies, cookie) } } } h := r.Header.Get("Content-Length") if len(h) > 0 { n, _ := strconv.Atoi64(h) b := make([]byte, n) io.ReadFull(r.Body, b) fmt.Println(string(b)) } else if method != "HEAD" { b, _ := ioutil.ReadAll(r.Body) fmt.Println(string(b)) } else { // TODO: streaming? } }
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) }