OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [net/] [http/] [cgi/] [child.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2011 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4
 
5
// This file implements CGI from the perspective of a child
6
// process.
7
 
8
package cgi
9
 
10
import (
11
        "bufio"
12
        "crypto/tls"
13
        "errors"
14
        "fmt"
15
        "io"
16
        "io/ioutil"
17
        "net"
18
        "net/http"
19
        "net/url"
20
        "os"
21
        "strconv"
22
        "strings"
23
)
24
 
25
// Request returns the HTTP request as represented in the current
26
// environment. This assumes the current program is being run
27
// by a web server in a CGI environment.
28
// The returned Request's Body is populated, if applicable.
29
func Request() (*http.Request, error) {
30
        r, err := RequestFromMap(envMap(os.Environ()))
31
        if err != nil {
32
                return nil, err
33
        }
34
        if r.ContentLength > 0 {
35
                r.Body = ioutil.NopCloser(io.LimitReader(os.Stdin, r.ContentLength))
36
        }
37
        return r, nil
38
}
39
 
40
func envMap(env []string) map[string]string {
41
        m := make(map[string]string)
42
        for _, kv := range env {
43
                if idx := strings.Index(kv, "="); idx != -1 {
44
                        m[kv[:idx]] = kv[idx+1:]
45
                }
46
        }
47
        return m
48
}
49
 
50
// RequestFromMap creates an http.Request from CGI variables.
51
// The returned Request's Body field is not populated.
52
func RequestFromMap(params map[string]string) (*http.Request, error) {
53
        r := new(http.Request)
54
        r.Method = params["REQUEST_METHOD"]
55
        if r.Method == "" {
56
                return nil, errors.New("cgi: no REQUEST_METHOD in environment")
57
        }
58
 
59
        r.Proto = params["SERVER_PROTOCOL"]
60
        var ok bool
61
        r.ProtoMajor, r.ProtoMinor, ok = http.ParseHTTPVersion(r.Proto)
62
        if !ok {
63
                return nil, errors.New("cgi: invalid SERVER_PROTOCOL version")
64
        }
65
 
66
        r.Close = true
67
        r.Trailer = http.Header{}
68
        r.Header = http.Header{}
69
 
70
        r.Host = params["HTTP_HOST"]
71
 
72
        if lenstr := params["CONTENT_LENGTH"]; lenstr != "" {
73
                clen, err := strconv.ParseInt(lenstr, 10, 64)
74
                if err != nil {
75
                        return nil, errors.New("cgi: bad CONTENT_LENGTH in environment: " + lenstr)
76
                }
77
                r.ContentLength = clen
78
        }
79
 
80
        if ct := params["CONTENT_TYPE"]; ct != "" {
81
                r.Header.Set("Content-Type", ct)
82
        }
83
 
84
        // Copy "HTTP_FOO_BAR" variables to "Foo-Bar" Headers
85
        for k, v := range params {
86
                if !strings.HasPrefix(k, "HTTP_") || k == "HTTP_HOST" {
87
                        continue
88
                }
89
                r.Header.Add(strings.Replace(k[5:], "_", "-", -1), v)
90
        }
91
 
92
        // TODO: cookies.  parsing them isn't exported, though.
93
 
94
        if r.Host != "" {
95
                // Hostname is provided, so we can reasonably construct a URL,
96
                // even if we have to assume 'http' for the scheme.
97
                rawurl := "http://" + r.Host + params["REQUEST_URI"]
98
                url, err := url.Parse(rawurl)
99
                if err != nil {
100
                        return nil, errors.New("cgi: failed to parse host and REQUEST_URI into a URL: " + rawurl)
101
                }
102
                r.URL = url
103
        }
104
        // Fallback logic if we don't have a Host header or the URL
105
        // failed to parse
106
        if r.URL == nil {
107
                uriStr := params["REQUEST_URI"]
108
                url, err := url.Parse(uriStr)
109
                if err != nil {
110
                        return nil, errors.New("cgi: failed to parse REQUEST_URI into a URL: " + uriStr)
111
                }
112
                r.URL = url
113
        }
114
 
115
        // There's apparently a de-facto standard for this.
116
        // http://docstore.mik.ua/orelly/linux/cgi/ch03_02.htm#ch03-35636
117
        if s := params["HTTPS"]; s == "on" || s == "ON" || s == "1" {
118
                r.TLS = &tls.ConnectionState{HandshakeComplete: true}
119
        }
120
 
121
        // Request.RemoteAddr has its port set by Go's standard http
122
        // server, so we do here too. We don't have one, though, so we
123
        // use a dummy one.
124
        r.RemoteAddr = net.JoinHostPort(params["REMOTE_ADDR"], "0")
125
 
126
        return r, nil
127
}
128
 
129
// Serve executes the provided Handler on the currently active CGI
130
// request, if any. If there's no current CGI environment
131
// an error is returned. The provided handler may be nil to use
132
// http.DefaultServeMux.
133
func Serve(handler http.Handler) error {
134
        req, err := Request()
135
        if err != nil {
136
                return err
137
        }
138
        if handler == nil {
139
                handler = http.DefaultServeMux
140
        }
141
        rw := &response{
142
                req:    req,
143
                header: make(http.Header),
144
                bufw:   bufio.NewWriter(os.Stdout),
145
        }
146
        handler.ServeHTTP(rw, req)
147
        if err = rw.bufw.Flush(); err != nil {
148
                return err
149
        }
150
        return nil
151
}
152
 
153
type response struct {
154
        req        *http.Request
155
        header     http.Header
156
        bufw       *bufio.Writer
157
        headerSent bool
158
}
159
 
160
func (r *response) Flush() {
161
        r.bufw.Flush()
162
}
163
 
164
func (r *response) Header() http.Header {
165
        return r.header
166
}
167
 
168
func (r *response) Write(p []byte) (n int, err error) {
169
        if !r.headerSent {
170
                r.WriteHeader(http.StatusOK)
171
        }
172
        return r.bufw.Write(p)
173
}
174
 
175
func (r *response) WriteHeader(code int) {
176
        if r.headerSent {
177
                // Note: explicitly using Stderr, as Stdout is our HTTP output.
178
                fmt.Fprintf(os.Stderr, "CGI attempted to write header twice on request for %s", r.req.URL)
179
                return
180
        }
181
        r.headerSent = true
182
        fmt.Fprintf(r.bufw, "Status: %d %s\r\n", code, http.StatusText(code))
183
 
184
        // Set a default Content-Type
185
        if _, hasType := r.header["Content-Type"]; !hasType {
186
                r.header.Add("Content-Type", "text/html; charset=utf-8")
187
        }
188
 
189
        r.header.Write(r.bufw)
190
        r.bufw.WriteString("\r\n")
191
        r.bufw.Flush()
192
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.