LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // HTTP server. See RFC 2616. | 5 // HTTP server. See RFC 2616. |
6 | 6 |
7 // TODO(rsc): | 7 // TODO(rsc): |
8 // logging | 8 // logging |
9 | 9 |
10 package http | 10 package http |
(...skipping 699 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 NotFound(w, r) | 710 NotFound(w, r) |
711 return | 711 return |
712 } | 712 } |
713 r.URL.Path = r.URL.Path[len(prefix):] | 713 r.URL.Path = r.URL.Path[len(prefix):] |
714 h.ServeHTTP(w, r) | 714 h.ServeHTTP(w, r) |
715 }) | 715 }) |
716 } | 716 } |
717 | 717 |
718 // Redirect replies to the request with a redirect to url, | 718 // Redirect replies to the request with a redirect to url, |
719 // which may be a path relative to the request path. | 719 // which may be a path relative to the request path. |
720 func Redirect(w ResponseWriter, r *Request, uri string, code int) { | 720 func Redirect(w ResponseWriter, r *Request, urlStr string, code int) { |
721 » if u, err := url.Parse(uri); err == nil { | 721 » if u, err := url.Parse(urlStr); err == nil { |
722 // If url was relative, make absolute by | 722 // If url was relative, make absolute by |
723 // combining with request path. | 723 // combining with request path. |
724 // The browser would probably do this for us, | 724 // The browser would probably do this for us, |
725 // but doing it ourselves is more reliable. | 725 // but doing it ourselves is more reliable. |
726 | 726 |
727 // NOTE(rsc): RFC 2616 says that the Location | 727 // NOTE(rsc): RFC 2616 says that the Location |
728 // line must be an absolute URI, like | 728 // line must be an absolute URI, like |
729 // "http://www.google.com/redirect/", | 729 // "http://www.google.com/redirect/", |
730 // not a path like "/redirect/". | 730 // not a path like "/redirect/". |
731 // Unfortunately, we don't know what to | 731 // Unfortunately, we don't know what to |
732 // put in the host name section to get the | 732 // put in the host name section to get the |
733 // client to connect to us again, so we can't | 733 // client to connect to us again, so we can't |
734 // know the right absolute URI to send back. | 734 // know the right absolute URI to send back. |
735 // Because of this problem, no one pays attention | 735 // Because of this problem, no one pays attention |
736 // to the RFC; they all send back just a new path. | 736 // to the RFC; they all send back just a new path. |
737 // So do we. | 737 // So do we. |
738 oldpath := r.URL.Path | 738 oldpath := r.URL.Path |
739 if oldpath == "" { // should not happen, but avoid a crash if it
does | 739 if oldpath == "" { // should not happen, but avoid a crash if it
does |
740 oldpath = "/" | 740 oldpath = "/" |
741 } | 741 } |
742 if u.Scheme == "" { | 742 if u.Scheme == "" { |
743 // no leading http://server | 743 // no leading http://server |
744 » » » if uri == "" || uri[0] != '/' { | 744 » » » if urlStr == "" || urlStr[0] != '/' { |
745 // make relative path absolute | 745 // make relative path absolute |
746 olddir, _ := path.Split(oldpath) | 746 olddir, _ := path.Split(oldpath) |
747 » » » » uri = olddir + uri | 747 » » » » urlStr = olddir + urlStr |
748 } | 748 } |
749 | 749 |
750 var query string | 750 var query string |
751 » » » if i := strings.Index(uri, "?"); i != -1 { | 751 » » » if i := strings.Index(urlStr, "?"); i != -1 { |
752 » » » » uri, query = uri[:i], uri[i:] | 752 » » » » urlStr, query = urlStr[:i], urlStr[i:] |
753 } | 753 } |
754 | 754 |
755 // clean up but preserve trailing slash | 755 // clean up but preserve trailing slash |
756 » » » trailing := uri[len(uri)-1] == '/' | 756 » » » trailing := urlStr[len(urlStr)-1] == '/' |
757 » » » uri = path.Clean(uri) | 757 » » » urlStr = path.Clean(urlStr) |
758 » » » if trailing && uri[len(uri)-1] != '/' { | 758 » » » if trailing && urlStr[len(urlStr)-1] != '/' { |
759 » » » » uri += "/" | 759 » » » » urlStr += "/" |
760 } | 760 } |
761 » » » uri += query | 761 » » » urlStr += query |
762 » » } | 762 » » } |
763 » } | 763 » } |
764 | 764 |
765 » w.Header().Set("Location", uri) | 765 » w.Header().Set("Location", urlStr) |
766 w.WriteHeader(code) | 766 w.WriteHeader(code) |
767 | 767 |
768 // RFC2616 recommends that a short note "SHOULD" be included in the | 768 // RFC2616 recommends that a short note "SHOULD" be included in the |
769 // response because older user agents may not understand 301/307. | 769 // response because older user agents may not understand 301/307. |
770 // Shouldn't send the response for POST or HEAD; that leaves GET. | 770 // Shouldn't send the response for POST or HEAD; that leaves GET. |
771 if r.Method == "GET" { | 771 if r.Method == "GET" { |
772 » » note := "<a href=\"" + htmlEscape(uri) + "\">" + statusText[code
] + "</a>.\n" | 772 » » note := "<a href=\"" + htmlEscape(urlStr) + "\">" + statusText[c
ode] + "</a>.\n" |
773 fmt.Fprintln(w, note) | 773 fmt.Fprintln(w, note) |
774 } | 774 } |
775 } | 775 } |
776 | 776 |
777 func htmlEscape(s string) string { | 777 func htmlEscape(s string) string { |
778 s = strings.Replace(s, "&", "&", -1) | 778 s = strings.Replace(s, "&", "&", -1) |
779 s = strings.Replace(s, "<", "<", -1) | 779 s = strings.Replace(s, "<", "<", -1) |
780 s = strings.Replace(s, ">", ">", -1) | 780 s = strings.Replace(s, ">", ">", -1) |
781 s = strings.Replace(s, "\"", """, -1) | 781 s = strings.Replace(s, "\"", """, -1) |
782 s = strings.Replace(s, "'", "'", -1) | 782 s = strings.Replace(s, "'", "'", -1) |
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1174 func (tw *timeoutWriter) WriteHeader(code int) { | 1174 func (tw *timeoutWriter) WriteHeader(code int) { |
1175 tw.mu.Lock() | 1175 tw.mu.Lock() |
1176 if tw.timedOut || tw.wroteHeader { | 1176 if tw.timedOut || tw.wroteHeader { |
1177 tw.mu.Unlock() | 1177 tw.mu.Unlock() |
1178 return | 1178 return |
1179 } | 1179 } |
1180 tw.wroteHeader = true | 1180 tw.wroteHeader = true |
1181 tw.mu.Unlock() | 1181 tw.mu.Unlock() |
1182 tw.w.WriteHeader(code) | 1182 tw.w.WriteHeader(code) |
1183 } | 1183 } |
LEFT | RIGHT |