From 3bf5cde38c840383b75ab7873fdb062aa2abe7ad Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Wed, 2 Sep 2020 20:36:53 +0800 Subject: [PATCH] adapt context --- pkg/adapter/context/acceptencoder.go | 45 +++++ pkg/adapter/context/context.go | 146 ++++++++++++++ pkg/adapter/context/input.go | 282 +++++++++++++++++++++++++++ pkg/adapter/context/output.go | 154 +++++++++++++++ pkg/adapter/context/renderer.go | 9 + pkg/adapter/context/response.go | 26 +++ 6 files changed, 662 insertions(+) create mode 100644 pkg/adapter/context/acceptencoder.go create mode 100644 pkg/adapter/context/context.go create mode 100644 pkg/adapter/context/input.go create mode 100644 pkg/adapter/context/output.go create mode 100644 pkg/adapter/context/renderer.go create mode 100644 pkg/adapter/context/response.go diff --git a/pkg/adapter/context/acceptencoder.go b/pkg/adapter/context/acceptencoder.go new file mode 100644 index 00000000..e578de45 --- /dev/null +++ b/pkg/adapter/context/acceptencoder.go @@ -0,0 +1,45 @@ +// Copyright 2015 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package context + +import ( + "io" + "net/http" + "os" + + "github.com/astaxie/beego/pkg/server/web/context" +) + +// InitGzip init the gzipcompress +func InitGzip(minLength, compressLevel int, methods []string) { + context.InitGzip(minLength, compressLevel, methods) +} + +// WriteFile reads from file and writes to writer by the specific encoding(gzip/deflate) +func WriteFile(encoding string, writer io.Writer, file *os.File) (bool, string, error) { + return context.WriteFile(encoding, writer, file) +} + +// WriteBody reads writes content to writer by the specific encoding(gzip/deflate) +func WriteBody(encoding string, writer io.Writer, content []byte) (bool, string, error) { + return context.WriteBody(encoding, writer, content) +} + +// ParseEncoding will extract the right encoding for response +// the Accept-Encoding's sec is here: +// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3 +func ParseEncoding(r *http.Request) string { + return context.ParseEncoding(r) +} diff --git a/pkg/adapter/context/context.go b/pkg/adapter/context/context.go new file mode 100644 index 00000000..f9d8c624 --- /dev/null +++ b/pkg/adapter/context/context.go @@ -0,0 +1,146 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package context provide the context utils +// Usage: +// +// import "github.com/astaxie/beego/context" +// +// ctx := context.Context{Request:req,ResponseWriter:rw} +// +// more docs http://beego.me/docs/module/context.md +package context + +import ( + "bufio" + "net" + "net/http" + + "github.com/astaxie/beego/pkg/server/web/context" +) + +// commonly used mime-types +const ( + ApplicationJSON = context.ApplicationJSON + ApplicationXML = context.ApplicationXML + ApplicationYAML = context.ApplicationYAML + TextXML = context.TextXML +) + +// NewContext return the Context with Input and Output +func NewContext() *Context { + return (*Context)(context.NewContext()) +} + +// Context Http request context struct including BeegoInput, BeegoOutput, http.Request and http.ResponseWriter. +// BeegoInput and BeegoOutput provides some api to operate request and response more easily. +type Context context.Context + +// Reset init Context, BeegoInput and BeegoOutput +func (ctx *Context) Reset(rw http.ResponseWriter, r *http.Request) { + (*context.Context)(ctx).Reset(rw, r) +} + +// Redirect does redirection to localurl with http header status code. +func (ctx *Context) Redirect(status int, localurl string) { + (*context.Context)(ctx).Redirect(status, localurl) +} + +// Abort stops this request. +// if beego.ErrorMaps exists, panic body. +func (ctx *Context) Abort(status int, body string) { + (*context.Context)(ctx).Abort(status, body) +} + +// WriteString Write string to response body. +// it sends response body. +func (ctx *Context) WriteString(content string) { + (*context.Context)(ctx).WriteString(content) +} + +// GetCookie Get cookie from request by a given key. +// It's alias of BeegoInput.Cookie. +func (ctx *Context) GetCookie(key string) string { + return (*context.Context)(ctx).GetCookie(key) +} + +// SetCookie Set cookie for response. +// It's alias of BeegoOutput.Cookie. +func (ctx *Context) SetCookie(name string, value string, others ...interface{}) { + (*context.Context)(ctx).SetCookie(name, value, others) +} + +// GetSecureCookie Get secure cookie from request by a given key. +func (ctx *Context) GetSecureCookie(Secret, key string) (string, bool) { + return (*context.Context)(ctx).GetSecureCookie(Secret, key) +} + +// SetSecureCookie Set Secure cookie for response. +func (ctx *Context) SetSecureCookie(Secret, name, value string, others ...interface{}) { + (*context.Context)(ctx).SetSecureCookie(Secret, name, value, others) +} + +// XSRFToken creates a xsrf token string and returns. +func (ctx *Context) XSRFToken(key string, expire int64) string { + return (*context.Context)(ctx).XSRFToken(key, expire) +} + +// CheckXSRFCookie checks xsrf token in this request is valid or not. +// the token can provided in request header "X-Xsrftoken" and "X-CsrfToken" +// or in form field value named as "_xsrf". +func (ctx *Context) CheckXSRFCookie() bool { + return (*context.Context)(ctx).CheckXSRFCookie() +} + +// RenderMethodResult renders the return value of a controller method to the output +func (ctx *Context) RenderMethodResult(result interface{}) { + (*context.Context)(ctx).RenderMethodResult(result) +} + +// Response is a wrapper for the http.ResponseWriter +// started set to true if response was written to then don't execute other handler +type Response context.Response + +// Write writes the data to the connection as part of an HTTP reply, +// and sets `started` to true. +// started means the response has sent out. +func (r *Response) Write(p []byte) (int, error) { + return (*context.Response)(r).Write(p) +} + +// WriteHeader sends an HTTP response header with status code, +// and sets `started` to true. +func (r *Response) WriteHeader(code int) { + (*context.Response)(r).WriteHeader(code) +} + +// Hijack hijacker for http +func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) { + return (*context.Response)(r).Hijack() +} + +// Flush http.Flusher +func (r *Response) Flush() { + (*context.Response)(r).Flush() +} + +// CloseNotify http.CloseNotifier +func (r *Response) CloseNotify() <-chan bool { + return (*context.Response)(r).CloseNotify() +} + +// Pusher http.Pusher +func (r *Response) Pusher() (pusher http.Pusher) { + return (*context.Response)(r).Pusher() +} diff --git a/pkg/adapter/context/input.go b/pkg/adapter/context/input.go new file mode 100644 index 00000000..a1d08855 --- /dev/null +++ b/pkg/adapter/context/input.go @@ -0,0 +1,282 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package context + +import ( + "github.com/astaxie/beego/pkg/server/web/context" +) + +// BeegoInput operates the http request header, data, cookie and body. +// it also contains router params and current session. +type BeegoInput context.BeegoInput + +// NewInput return BeegoInput generated by Context. +func NewInput() *BeegoInput { + return (*BeegoInput)(context.NewInput()) +} + +// Reset init the BeegoInput +func (input *BeegoInput) Reset(ctx *Context) { + (*context.BeegoInput)(input).Reset((*context.Context)(ctx)) +} + +// Protocol returns request protocol name, such as HTTP/1.1 . +func (input *BeegoInput) Protocol() string { + return (*context.BeegoInput)(input).Protocol() +} + +// URI returns full request url with query string, fragment. +func (input *BeegoInput) URI() string { + return input.Context.Request.RequestURI +} + +// URL returns request url path (without query string, fragment). +func (input *BeegoInput) URL() string { + return (*context.BeegoInput)(input).URL() +} + +// Site returns base site url as scheme://domain type. +func (input *BeegoInput) Site() string { + return (*context.BeegoInput)(input).Site() +} + +// Scheme returns request scheme as "http" or "https". +func (input *BeegoInput) Scheme() string { + return (*context.BeegoInput)(input).Scheme() +} + +// Domain returns host name. +// Alias of Host method. +func (input *BeegoInput) Domain() string { + return (*context.BeegoInput)(input).Domain() +} + +// Host returns host name. +// if no host info in request, return localhost. +func (input *BeegoInput) Host() string { + return (*context.BeegoInput)(input).Host() +} + +// Method returns http request method. +func (input *BeegoInput) Method() string { + return (*context.BeegoInput)(input).Method() +} + +// Is returns boolean of this request is on given method, such as Is("POST"). +func (input *BeegoInput) Is(method string) bool { + return (*context.BeegoInput)(input).Is(method) +} + +// IsGet Is this a GET method request? +func (input *BeegoInput) IsGet() bool { + return (*context.BeegoInput)(input).IsGet() +} + +// IsPost Is this a POST method request? +func (input *BeegoInput) IsPost() bool { + return (*context.BeegoInput)(input).IsPost() +} + +// IsHead Is this a Head method request? +func (input *BeegoInput) IsHead() bool { + return (*context.BeegoInput)(input).IsHead() +} + +// IsOptions Is this a OPTIONS method request? +func (input *BeegoInput) IsOptions() bool { + return (*context.BeegoInput)(input).IsOptions() +} + +// IsPut Is this a PUT method request? +func (input *BeegoInput) IsPut() bool { + return (*context.BeegoInput)(input).IsPut() +} + +// IsDelete Is this a DELETE method request? +func (input *BeegoInput) IsDelete() bool { + return (*context.BeegoInput)(input).IsDelete() +} + +// IsPatch Is this a PATCH method request? +func (input *BeegoInput) IsPatch() bool { + return (*context.BeegoInput)(input).IsPatch() +} + +// IsAjax returns boolean of this request is generated by ajax. +func (input *BeegoInput) IsAjax() bool { + return (*context.BeegoInput)(input).IsAjax() +} + +// IsSecure returns boolean of this request is in https. +func (input *BeegoInput) IsSecure() bool { + return (*context.BeegoInput)(input).IsSecure() +} + +// IsWebsocket returns boolean of this request is in webSocket. +func (input *BeegoInput) IsWebsocket() bool { + return (*context.BeegoInput)(input).IsWebsocket() +} + +// IsUpload returns boolean of whether file uploads in this request or not.. +func (input *BeegoInput) IsUpload() bool { + return (*context.BeegoInput)(input).IsUpload() +} + +// AcceptsHTML Checks if request accepts html response +func (input *BeegoInput) AcceptsHTML() bool { + return (*context.BeegoInput)(input).AcceptsHTML() +} + +// AcceptsXML Checks if request accepts xml response +func (input *BeegoInput) AcceptsXML() bool { + return (*context.BeegoInput)(input).AcceptsXML() +} + +// AcceptsJSON Checks if request accepts json response +func (input *BeegoInput) AcceptsJSON() bool { + return (*context.BeegoInput)(input).AcceptsJSON() +} + +// AcceptsYAML Checks if request accepts json response +func (input *BeegoInput) AcceptsYAML() bool { + return (*context.BeegoInput)(input).AcceptsYAML() +} + +// IP returns request client ip. +// if in proxy, return first proxy id. +// if error, return RemoteAddr. +func (input *BeegoInput) IP() string { + return (*context.BeegoInput)(input).IP() +} + +// Proxy returns proxy client ips slice. +func (input *BeegoInput) Proxy() []string { + return (*context.BeegoInput)(input).Proxy() +} + +// Referer returns http referer header. +func (input *BeegoInput) Referer() string { + return (*context.BeegoInput)(input).Referer() +} + +// Refer returns http referer header. +func (input *BeegoInput) Refer() string { + return (*context.BeegoInput)(input).Refer() +} + +// SubDomains returns sub domain string. +// if aa.bb.domain.com, returns aa.bb . +func (input *BeegoInput) SubDomains() string { + return (*context.BeegoInput)(input).SubDomains() +} + +// Port returns request client port. +// when error or empty, return 80. +func (input *BeegoInput) Port() int { + return (*context.BeegoInput)(input).Port() +} + +// UserAgent returns request client user agent string. +func (input *BeegoInput) UserAgent() string { + return (*context.BeegoInput)(input).UserAgent() +} + +// ParamsLen return the length of the params +func (input *BeegoInput) ParamsLen() int { + return (*context.BeegoInput)(input).ParamsLen() +} + +// Param returns router param by a given key. +func (input *BeegoInput) Param(key string) string { + return (*context.BeegoInput)(input).Param(key) +} + +// Params returns the map[key]value. +func (input *BeegoInput) Params() map[string]string { + return (*context.BeegoInput)(input).Params() +} + +// SetParam will set the param with key and value +func (input *BeegoInput) SetParam(key, val string) { + (*context.BeegoInput)(input).SetParam(key, val) +} + +// ResetParams clears any of the input's Params +// This function is used to clear parameters so they may be reset between filter +// passes. +func (input *BeegoInput) ResetParams() { + (*context.BeegoInput)(input).ResetParams() +} + +// Query returns input data item string by a given string. +func (input *BeegoInput) Query(key string) string { + return (*context.BeegoInput)(input).Query(key) +} + +// Header returns request header item string by a given string. +// if non-existed, return empty string. +func (input *BeegoInput) Header(key string) string { + return (*context.BeegoInput)(input).Header(key) +} + +// Cookie returns request cookie item string by a given key. +// if non-existed, return empty string. +func (input *BeegoInput) Cookie(key string) string { + return (*context.BeegoInput)(input).Cookie(key) +} + +// Session returns current session item value by a given key. +// if non-existed, return nil. +func (input *BeegoInput) Session(key interface{}) interface{} { + return (*context.BeegoInput)(input).Session(key) +} + +// CopyBody returns the raw request body data as bytes. +func (input *BeegoInput) CopyBody(MaxMemory int64) []byte { + return (*context.BeegoInput)(input).CopyBody(MaxMemory) +} + +// Data return the implicit data in the input +func (input *BeegoInput) Data() map[interface{}]interface{} { + return (*context.BeegoInput)(input).Data() +} + +// GetData returns the stored data in this context. +func (input *BeegoInput) GetData(key interface{}) interface{} { + return (*context.BeegoInput)(input).GetData(key) +} + +// SetData stores data with given key in this context. +// This data are only available in this context. +func (input *BeegoInput) SetData(key, val interface{}) { + (*context.BeegoInput)(input).SetData(key, val) +} + +// ParseFormOrMulitForm parseForm or parseMultiForm based on Content-type +func (input *BeegoInput) ParseFormOrMulitForm(maxMemory int64) error { + return (*context.BeegoInput)(input).ParseFormOrMulitForm(maxMemory) +} + +// Bind data from request.Form[key] to dest +// like /?id=123&isok=true&ft=1.2&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&user.Name=astaxie +// var id int beegoInput.Bind(&id, "id") id ==123 +// var isok bool beegoInput.Bind(&isok, "isok") isok ==true +// var ft float64 beegoInput.Bind(&ft, "ft") ft ==1.2 +// ol := make([]int, 0, 2) beegoInput.Bind(&ol, "ol") ol ==[1 2] +// ul := make([]string, 0, 2) beegoInput.Bind(&ul, "ul") ul ==[str array] +// user struct{Name} beegoInput.Bind(&user, "user") user == {Name:"astaxie"} +func (input *BeegoInput) Bind(dest interface{}, key string) error { + return (*context.BeegoInput)(input).Bind(dest, key) +} diff --git a/pkg/adapter/context/output.go b/pkg/adapter/context/output.go new file mode 100644 index 00000000..8e2a7f7d --- /dev/null +++ b/pkg/adapter/context/output.go @@ -0,0 +1,154 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package context + +import ( + "github.com/astaxie/beego/pkg/server/web/context" +) + +// BeegoOutput does work for sending response header. +type BeegoOutput context.BeegoOutput + +// NewOutput returns new BeegoOutput. +// it contains nothing now. +func NewOutput() *BeegoOutput { + return (*BeegoOutput)(context.NewOutput()) +} + +// Reset init BeegoOutput +func (output *BeegoOutput) Reset(ctx *Context) { + (*context.BeegoOutput)(output).Reset((*context.Context)(ctx)) +} + +// Header sets response header item string via given key. +func (output *BeegoOutput) Header(key, val string) { + (*context.BeegoOutput)(output).Header(key, val) +} + +// Body sets response body content. +// if EnableGzip, compress content string. +// it sends out response body directly. +func (output *BeegoOutput) Body(content []byte) error { + return (*context.BeegoOutput)(output).Body(content) +} + +// Cookie sets cookie value via given key. +// others are ordered as cookie's max age time, path,domain, secure and httponly. +func (output *BeegoOutput) Cookie(name string, value string, others ...interface{}) { + (*context.BeegoOutput)(output).Cookie(name, value, others) +} + +// JSON writes json to response body. +// if encoding is true, it converts utf-8 to \u0000 type. +func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, encoding bool) error { + return (*context.BeegoOutput)(output).JSON(data, hasIndent, encoding) +} + +// YAML writes yaml to response body. +func (output *BeegoOutput) YAML(data interface{}) error { + return (*context.BeegoOutput)(output).YAML(data) +} + +// JSONP writes jsonp to response body. +func (output *BeegoOutput) JSONP(data interface{}, hasIndent bool) error { + return (*context.BeegoOutput)(output).JSONP(data, hasIndent) +} + +// XML writes xml string to response body. +func (output *BeegoOutput) XML(data interface{}, hasIndent bool) error { + return (*context.BeegoOutput)(output).XML(data, hasIndent) +} + +// ServeFormatted serve YAML, XML OR JSON, depending on the value of the Accept header +func (output *BeegoOutput) ServeFormatted(data interface{}, hasIndent bool, hasEncode ...bool) { + (*context.BeegoOutput)(output).ServeFormatted(data, hasIndent, hasEncode...) +} + +// Download forces response for download file. +// it prepares the download response header automatically. +func (output *BeegoOutput) Download(file string, filename ...string) { + (*context.BeegoOutput)(output).Download(file, filename...) +} + +// ContentType sets the content type from ext string. +// MIME type is given in mime package. +func (output *BeegoOutput) ContentType(ext string) { + (*context.BeegoOutput)(output).ContentType(ext) +} + +// SetStatus sets response status code. +// It writes response header directly. +func (output *BeegoOutput) SetStatus(status int) { + (*context.BeegoOutput)(output).SetStatus(status) +} + +// IsCachable returns boolean of this request is cached. +// HTTP 304 means cached. +func (output *BeegoOutput) IsCachable() bool { + return (*context.BeegoOutput)(output).IsCachable() +} + +// IsEmpty returns boolean of this request is empty. +// HTTP 201,204 and 304 means empty. +func (output *BeegoOutput) IsEmpty() bool { + return (*context.BeegoOutput)(output).IsEmpty() +} + +// IsOk returns boolean of this request runs well. +// HTTP 200 means ok. +func (output *BeegoOutput) IsOk() bool { + return (*context.BeegoOutput)(output).IsOk() +} + +// IsSuccessful returns boolean of this request runs successfully. +// HTTP 2xx means ok. +func (output *BeegoOutput) IsSuccessful() bool { + return (*context.BeegoOutput)(output).IsSuccessful() +} + +// IsRedirect returns boolean of this request is redirection header. +// HTTP 301,302,307 means redirection. +func (output *BeegoOutput) IsRedirect() bool { + return (*context.BeegoOutput)(output).IsRedirect() +} + +// IsForbidden returns boolean of this request is forbidden. +// HTTP 403 means forbidden. +func (output *BeegoOutput) IsForbidden() bool { + return (*context.BeegoOutput)(output).IsForbidden() +} + +// IsNotFound returns boolean of this request is not found. +// HTTP 404 means not found. +func (output *BeegoOutput) IsNotFound() bool { + return (*context.BeegoOutput)(output).IsNotFound() +} + +// IsClientError returns boolean of this request client sends error data. +// HTTP 4xx means client error. +func (output *BeegoOutput) IsClientError() bool { + return (*context.BeegoOutput)(output).IsClientError() +} + +// IsServerError returns boolean of this server handler errors. +// HTTP 5xx means server internal error. +func (output *BeegoOutput) IsServerError() bool { + return (*context.BeegoOutput)(output).IsServerError() +} + +// Session sets session item value with given key. +func (output *BeegoOutput) Session(name interface{}, value interface{}) { + (*context.BeegoOutput)(output).Session(name, value) +} diff --git a/pkg/adapter/context/renderer.go b/pkg/adapter/context/renderer.go new file mode 100644 index 00000000..7e352007 --- /dev/null +++ b/pkg/adapter/context/renderer.go @@ -0,0 +1,9 @@ +package context + +import ( + "github.com/astaxie/beego/pkg/server/web/context" +) + +// Renderer defines an http response renderer +type Renderer context.Renderer + diff --git a/pkg/adapter/context/response.go b/pkg/adapter/context/response.go new file mode 100644 index 00000000..24e196a4 --- /dev/null +++ b/pkg/adapter/context/response.go @@ -0,0 +1,26 @@ +package context + +import ( + "net/http" + "strconv" +) + +const ( + // BadRequest indicates http error 400 + BadRequest StatusCode = http.StatusBadRequest + + // NotFound indicates http error 404 + NotFound StatusCode = http.StatusNotFound +) + +// StatusCode sets the http response status code +type StatusCode int + +func (s StatusCode) Error() string { + return strconv.Itoa(int(s)) +} + +// Render sets the http status code +func (s StatusCode) Render(ctx *Context) { + ctx.Output.SetStatus(int(s)) +}