├── README.md ├── config.go ├── example └── example.go ├── oauth.go ├── oauth_qq.go ├── oauth_test.go ├── oauth_wechat.go ├── oauth_weibo.go └── vendor └── httplib ├── httplib.go └── httplib_test.go /README.md: -------------------------------------------------------------------------------- 1 | # simpleoauth 2 | 3 | Golang实现几大主流平台的oauth2.0认证(目前仅支持QQ,微信,微博) 4 | 5 | 使用方法: 6 | 在config.go中配置好相关信息后 7 | 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "simpleoauth" 13 | ) 14 | 15 | func main() { 16 | m, _ := simpleoauth.NewManager("qq") 17 | result := m.Authorize("此处填入认证通过后,第三方平台跳转带回来的CODE") 18 | fmt.Println(result) 19 | } 20 | 21 | 返回结果为: 22 | 23 | type AuthorizeResult struct{ 24 | Result bool //认证成功或失败 25 | Userinfo map[string]interface{} //返回用户信息等基本资料 26 | } -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | package simpleoauth 2 | 3 | const( 4 | Wechatappkey = "" 5 | Wechatappsecret = "" 6 | 7 | QQappkey = "" 8 | QQappsecret = "" 9 | QQRedirectUrl = "" 10 | 11 | Weiboappkey = "" 12 | Weiboappsecret = "" 13 | WeiboRedirectUrl = "" 14 | ) 15 | -------------------------------------------------------------------------------- /example/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "simpleoauth" 6 | ) 7 | 8 | func main() { 9 | m, _ := simpleoauth.NewManager("qq") 10 | result := m.Authorize("此处填入认证通过后,第三方平台跳转带回来的CODE") 11 | fmt.Println(result) 12 | } 13 | -------------------------------------------------------------------------------- /oauth.go: -------------------------------------------------------------------------------- 1 | package simpleoauth 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | var oauthes= make(map[string]OAuth) 8 | 9 | type OAuth interface{ 10 | GetAccesstoken(code string) map[string]interface{} 11 | GetUserinfo(accesstoken string, openid string) map[string]interface{} 12 | Authorize(code string) AuthorizeResult 13 | InitOAuth() 14 | } 15 | 16 | func ReisterPlatform(name string, oauth OAuth){ 17 | if oauth == nil { 18 | panic("Register simpleoauth instance is nil") 19 | } 20 | _, dup := oauthes[name] 21 | if dup{ 22 | panic("The platform has registered already") 23 | } 24 | oauthes[name] = oauth 25 | } 26 | 27 | type Manager struct { 28 | oauth OAuth 29 | } 30 | 31 | func NewManager(platformName string)(*Manager, error){ 32 | oauth, ok := oauthes[platformName] 33 | if !ok{ 34 | return nil, fmt.Errorf("unknown platform %q", platformName) 35 | } 36 | oauth.InitOAuth() 37 | return &Manager{oauth}, nil 38 | } 39 | 40 | func (m *Manager)Authorize(code string) AuthorizeResult{ 41 | return m.oauth.Authorize(code) 42 | } 43 | 44 | type AuthorizeResult struct{ 45 | Result bool 46 | Userinfo map[string]interface{} 47 | } 48 | -------------------------------------------------------------------------------- /oauth_qq.go: -------------------------------------------------------------------------------- 1 | package simpleoauth 2 | 3 | import ( 4 | "httplib" 5 | "strings" 6 | "encoding/json" 7 | ) 8 | 9 | const qq_getaccesstoken_url = "https://graph.qq.com/oauth2.0/token" 10 | const qq_getuserinfo_url = "https://graph.qq.com/user/get_user_info" 11 | const qq_openid_url = "https://graph.qq.com/oauth2.0/me" 12 | 13 | var qqOAuth = &QQOAuth{} 14 | 15 | type QQOAuth struct { 16 | appkey string 17 | appsecret string 18 | redirect_url string 19 | } 20 | 21 | func (oauth *QQOAuth) GetAccesstoken(code string) map[string]interface{}{ 22 | request:= httplib.Get(qq_getaccesstoken_url) 23 | request.Param("grant_type","authorization_code") 24 | request.Param("client_id",oauth.appkey) 25 | request.Param("client_secret",oauth.appsecret) 26 | request.Param("code",code) 27 | request.Param("redirect_uri", oauth.redirect_url) 28 | 29 | response, err := request.String() 30 | if err != nil { 31 | return nil 32 | } 33 | if strings.Contains(response, "callback"){ 34 | return nil 35 | } 36 | temp := strings.Split(response, "&")[0] 37 | accesstoken := strings.Split(temp, "=")[1] 38 | return map[string]interface{}{"access_token" : accesstoken} 39 | } 40 | 41 | func (oauth *QQOAuth) GetOpenid(accesstoken string) map[string]interface{}{ 42 | request:= httplib.Get(qq_openid_url) 43 | request.Param("access_token",accesstoken) 44 | request.Param("unionid","1") 45 | responseStr, _ := request.String() 46 | var response map[string]interface{} 47 | json.Unmarshal([]byte(responseStr[10:len(responseStr)-3]),&response) 48 | return response 49 | } 50 | 51 | func (oauth *QQOAuth) GetUserinfo(accesstoken string, openid string) map[string]interface{}{ 52 | request:= httplib.Get(qq_getuserinfo_url) 53 | request.Param("access_token",accesstoken) 54 | request.Param("oauth_consumer_key",oauth.appkey) 55 | request.Param("openid",openid) 56 | var response map[string]interface{} 57 | err := request.ToJson(&response) 58 | if err != nil { 59 | return nil 60 | } 61 | return response 62 | } 63 | 64 | func (oauth *QQOAuth) Authorize(code string) AuthorizeResult{ 65 | accesstokenResponse := oauth.GetAccesstoken(code) 66 | if accesstokenResponse == nil{ 67 | return AuthorizeResult{false, nil} 68 | } 69 | accesstoken := accesstokenResponse["access_token"].(string) 70 | openidResponse := oauth.GetOpenid(accesstoken) 71 | if _, ok := openidResponse["error"]; ok { //获取openid接口返回错误 72 | return AuthorizeResult{false, nil} 73 | } 74 | openid := openidResponse["openid"].(string) 75 | unionid := openidResponse["unionid"].(string) 76 | 77 | getuserinfoResult := oauth.GetUserinfo(accesstoken, openid) 78 | if getuserinfoResult == nil{ 79 | return AuthorizeResult{false, nil} 80 | } 81 | var sex int 82 | gender, ok := getuserinfoResult["gender"] 83 | if !ok { 84 | sex = 1 85 | } 86 | if gender.(string) == "女" { 87 | sex = 2 88 | }else{ 89 | sex = 1 90 | } 91 | return AuthorizeResult{true, map[string]interface{}{ 92 | "nickname":getuserinfoResult["nickname"].(string), 93 | "openid":openid, 94 | "sex":sex, 95 | "headimgurl":getuserinfoResult["figureurl_qq_1"].(string), // QQ头像 40x40尺寸 96 | "unionid":unionid}} 97 | } 98 | 99 | func (oauth *QQOAuth) InitOAuth(){ 100 | oauth.appkey = QQappkey 101 | oauth.appsecret = QQappsecret 102 | oauth.redirect_url = QQRedirectUrl 103 | } 104 | 105 | func init(){ 106 | ReisterPlatform("qq", qqOAuth) 107 | } 108 | -------------------------------------------------------------------------------- /oauth_test.go: -------------------------------------------------------------------------------- 1 | package simpleoauth 2 | 3 | import ( 4 | "testing" 5 | "fmt" 6 | ) 7 | 8 | func TestManager_Authorize(t *testing.T) { 9 | m, _ := NewManager("wechat") 10 | fmt.Println(m.Authorize("0210r0wV1HFv6T0f6qwV154KvV10r0wJ")) 11 | } 12 | 13 | func TestQQOAuth_GetAccesstoken(t *testing.T) { 14 | m, _ := NewManager("qq") 15 | m.oauth.GetAccesstoken("7B6DEDC59F858A0B63F4D2C42F6D0E71") 16 | } 17 | 18 | func TestQQOAuth_Authorize(t *testing.T) { 19 | m, _ := NewManager("qq") 20 | m.oauth.Authorize("2EB4B7C981FAFCC1BAD97A2B2466EEDD") 21 | } 22 | 23 | func TestWeiboOAuth_Authorize(t *testing.T) { 24 | m, _ := NewManager("weibo") 25 | fmt.Println(m.oauth.Authorize("63033d599df176a23cac0363db0787cf")) 26 | } -------------------------------------------------------------------------------- /oauth_wechat.go: -------------------------------------------------------------------------------- 1 | package simpleoauth 2 | 3 | import ( 4 | "httplib" 5 | ) 6 | 7 | const wechat_getaccesstoken_url = "https://api.weixin.qq.com/sns/oauth2/access_token" 8 | const wechat_getuserinfo_url = "https://api.weixin.qq.com/sns/userinfo" 9 | 10 | var wechatOAuth = &WechatOAuth{} 11 | 12 | type WechatOAuth struct { 13 | appkey string 14 | appsecret string 15 | } 16 | 17 | func (oauth *WechatOAuth) GetAccesstoken(code string) map[string]interface{}{ 18 | request:= httplib.Get(wechat_getaccesstoken_url) 19 | request.Param("appid",oauth.appkey) 20 | request.Param("secret",oauth.appsecret) 21 | request.Param("code",code) 22 | request.Param("grant_type","authorization_code") 23 | var response map[string]interface{} 24 | err := request.ToJson(&response) 25 | if err != nil { 26 | return nil 27 | } 28 | return response 29 | } 30 | 31 | func (oauth *WechatOAuth) GetUserinfo(accesstoken string, openid string) map[string]interface{}{ 32 | request:= httplib.Get(wechat_getuserinfo_url) 33 | request.Param("access_token", accesstoken) 34 | request.Param("openid", openid) 35 | var response map[string]interface{} 36 | err := request.ToJson(&response) 37 | if err != nil { 38 | return nil 39 | } 40 | return response 41 | } 42 | 43 | func (oauth *WechatOAuth) Authorize(code string) AuthorizeResult{ 44 | accesstokenResponse := oauth.GetAccesstoken(code) 45 | if accesstokenResponse == nil{ 46 | return AuthorizeResult{false, nil} 47 | } 48 | _, ok := accesstokenResponse["errcode"] //获取accesstoken接口返回错误码 49 | if ok { 50 | return AuthorizeResult{false, nil} 51 | } 52 | openid := accesstokenResponse["openid"].(string) 53 | accesstoken := accesstokenResponse["access_token"].(string) 54 | getuserinfoResult := oauth.GetUserinfo(accesstoken, openid) 55 | if getuserinfoResult == nil { 56 | return AuthorizeResult{false, nil} 57 | } 58 | _, ok = getuserinfoResult["errcode"] //获取用户信息接口返回错误码 59 | if ok { 60 | return AuthorizeResult{false, nil} 61 | } 62 | 63 | return AuthorizeResult{true, map[string]interface{}{ 64 | "nickname":getuserinfoResult["nickname"].(string), 65 | "openid":getuserinfoResult["openid"].(string), 66 | "sex":getuserinfoResult["sex"].(float64), 67 | "headimgurl":getuserinfoResult["headimgurl"].(string), 68 | "unionid":getuserinfoResult["unionid"].(string)}} 69 | } 70 | 71 | func (oauth *WechatOAuth) InitOAuth(){ 72 | oauth.appkey = Wechatappkey 73 | oauth.appsecret = Wechatappsecret 74 | } 75 | 76 | 77 | func init(){ 78 | ReisterPlatform("wechat", wechatOAuth) 79 | } 80 | 81 | -------------------------------------------------------------------------------- /oauth_weibo.go: -------------------------------------------------------------------------------- 1 | package simpleoauth 2 | 3 | import ( 4 | "fmt" 5 | "httplib" 6 | ) 7 | 8 | const weibo_getaccesstoken_url = "https://api.weibo.com/oauth2/access_token" 9 | const weibo_getuserinfo_url = "https://api.weibo.com/2/users/show.json" 10 | 11 | var weiboOAuth = &WeiboOAuth{} 12 | 13 | type WeiboOAuth struct { 14 | appkey string 15 | appsecret string 16 | redirect_url string 17 | } 18 | 19 | func (oauth *WeiboOAuth) GetAccesstoken(code string) map[string]interface{}{ 20 | request:= httplib.Post(weibo_getaccesstoken_url) 21 | request.Param("client_id", oauth.appkey) 22 | request.Param("client_secret", oauth.appsecret) 23 | request.Param("grant_type", "authorization_code") 24 | request.Param("code", code) 25 | request.Param("redirect_uri", oauth.redirect_url) 26 | var response map[string]interface{} 27 | err := request.ToJson(&response) 28 | if err != nil { 29 | return nil 30 | } 31 | return response 32 | } 33 | 34 | func (oauth *WeiboOAuth) GetUserinfo(accesstoken string, openid string) map[string]interface{}{ 35 | request:= httplib.Get(weibo_getuserinfo_url) 36 | request.Param("access_token", accesstoken) 37 | request.Param("uid", openid) 38 | var response map[string]interface{} 39 | err := request.ToJson(&response) 40 | if err != nil { 41 | return nil 42 | } 43 | return response 44 | } 45 | 46 | func (oauth *WeiboOAuth) Authorize(code string) AuthorizeResult{ 47 | accesstokenResponse := oauth.GetAccesstoken(code) 48 | if accesstokenResponse == nil{ 49 | return AuthorizeResult{false, nil} 50 | } 51 | _, ok := accesstokenResponse["error_code"] //获取accesstoken接口返回错误码 52 | if ok { 53 | return AuthorizeResult{false, nil} 54 | } 55 | openid := accesstokenResponse["uid"].(string) 56 | accesstoken := accesstokenResponse["access_token"].(string) 57 | getuserinfoResult := oauth.GetUserinfo(accesstoken, openid) 58 | fmt.Println(getuserinfoResult) 59 | if getuserinfoResult == nil { 60 | return AuthorizeResult{false, nil} 61 | } 62 | _, ok = getuserinfoResult["error_code"] //获取用户信息接口返回错误码 63 | if ok { 64 | return AuthorizeResult{false, nil} 65 | } 66 | var sex int 67 | if getuserinfoResult["gender"].(string) == "m"{ 68 | sex = 1 69 | }else if getuserinfoResult["gender"].(string) == "f"{ 70 | sex = 2 71 | }else if getuserinfoResult["gender"].(string) == "n"{ 72 | sex = 0 73 | } 74 | return AuthorizeResult{true, map[string]interface{}{ 75 | "nickname":getuserinfoResult["screen_name"].(string), 76 | "openid":openid, 77 | "sex":sex, 78 | "headimgurl":getuserinfoResult["profile_image_url"].(string), 79 | "unionid":""}} 80 | } 81 | 82 | func (oauth *WeiboOAuth) InitOAuth(){ 83 | oauth.appkey = Weiboappkey 84 | oauth.appsecret = Weiboappsecret 85 | oauth.redirect_url = WeiboRedirectUrl 86 | } 87 | 88 | 89 | func init(){ 90 | ReisterPlatform("weibo", weiboOAuth) 91 | } 92 | 93 | -------------------------------------------------------------------------------- /vendor/httplib/httplib.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Beego Authors. All rights reserved. 2 | // Copyright 2014 The Gogs Authors. All rights reserved. 3 | // Use of this source code is governed by a MIT-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package httplib 7 | 8 | import ( 9 | "bytes" 10 | "crypto/tls" 11 | "encoding/json" 12 | "encoding/xml" 13 | "io" 14 | "io/ioutil" 15 | "log" 16 | "mime/multipart" 17 | "net" 18 | "net/http" 19 | "net/http/cookiejar" 20 | "net/http/httputil" 21 | "net/url" 22 | "os" 23 | "strings" 24 | "sync" 25 | "time" 26 | ) 27 | 28 | var defaultSetting = Settings{false, "minigws", 3 * time.Second, 3 * time.Second, nil, nil, nil, false} 29 | var defaultCookieJar http.CookieJar 30 | var settingMutex sync.Mutex 31 | 32 | // createDefaultCookie creates a global cookiejar to store cookies. 33 | func createDefaultCookie() { 34 | settingMutex.Lock() 35 | defer settingMutex.Unlock() 36 | defaultCookieJar, _ = cookiejar.New(nil) 37 | } 38 | 39 | // Overwrite default settings 40 | func SetDefaultSetting(setting Settings) { 41 | settingMutex.Lock() 42 | defer settingMutex.Unlock() 43 | defaultSetting = setting 44 | if defaultSetting.ConnectTimeout == 0 { 45 | defaultSetting.ConnectTimeout = 60 * time.Second 46 | } 47 | if defaultSetting.ReadWriteTimeout == 0 { 48 | defaultSetting.ReadWriteTimeout = 60 * time.Second 49 | } 50 | } 51 | 52 | // return *Request with specific method 53 | func newRequest(url, method string) *Request { 54 | var resp http.Response 55 | req := http.Request{ 56 | Method: method, 57 | Header: make(http.Header), 58 | Proto: "HTTP/1.1", 59 | ProtoMajor: 1, 60 | ProtoMinor: 1, 61 | } 62 | return &Request{url, &req, map[string]string{}, map[string]string{}, defaultSetting, &resp, nil} 63 | } 64 | 65 | // Get returns *Request with GET method. 66 | func Get(url string) *Request { 67 | return newRequest(url, "GET") 68 | } 69 | 70 | // Post returns *Request with POST method. 71 | func Post(url string) *Request { 72 | return newRequest(url, "POST") 73 | } 74 | 75 | // Put returns *Request with PUT method. 76 | func Put(url string) *Request { 77 | return newRequest(url, "PUT") 78 | } 79 | 80 | // Delete returns *Request DELETE method. 81 | func Delete(url string) *Request { 82 | return newRequest(url, "DELETE") 83 | } 84 | 85 | // Head returns *Request with HEAD method. 86 | func Head(url string) *Request { 87 | return newRequest(url, "HEAD") 88 | } 89 | 90 | type Settings struct { 91 | ShowDebug bool 92 | UserAgent string 93 | ConnectTimeout time.Duration 94 | ReadWriteTimeout time.Duration 95 | TlsClientConfig *tls.Config 96 | Proxy func(*http.Request) (*url.URL, error) 97 | Transport http.RoundTripper 98 | EnableCookie bool 99 | } 100 | 101 | // HttpRequest provides more useful methods for requesting one url than http.Request. 102 | type Request struct { 103 | url string 104 | req *http.Request 105 | params map[string]string 106 | files map[string]string 107 | setting Settings 108 | resp *http.Response 109 | body []byte 110 | } 111 | 112 | // Change request settings 113 | func (r *Request) Setting(setting Settings) *Request { 114 | r.setting = setting 115 | return r 116 | } 117 | 118 | // SetBasicAuth sets the request's Authorization header to use HTTP Basic Authentication with the provided username and password. 119 | func (r *Request) SetBasicAuth(username, password string) *Request { 120 | r.req.SetBasicAuth(username, password) 121 | return r 122 | } 123 | 124 | // SetEnableCookie sets enable/disable cookiejar 125 | func (r *Request) SetEnableCookie(enable bool) *Request { 126 | r.setting.EnableCookie = enable 127 | return r 128 | } 129 | 130 | // SetUserAgent sets User-Agent header field 131 | func (r *Request) SetUserAgent(useragent string) *Request { 132 | r.setting.UserAgent = useragent 133 | return r 134 | } 135 | 136 | // Debug sets show debug or not when executing request. 137 | func (r *Request) Debug(isdebug bool) *Request { 138 | r.setting.ShowDebug = isdebug 139 | return r 140 | } 141 | 142 | // SetTimeout sets connect time out and read-write time out for BeegoRequest. 143 | func (r *Request) SetTimeout(connectTimeout, readWriteTimeout time.Duration) *Request { 144 | r.setting.ConnectTimeout = connectTimeout 145 | r.setting.ReadWriteTimeout = readWriteTimeout 146 | return r 147 | } 148 | 149 | // SetTLSClientConfig sets tls connection configurations if visiting https url. 150 | func (r *Request) SetTLSClientConfig(config *tls.Config) *Request { 151 | r.setting.TlsClientConfig = config 152 | return r 153 | } 154 | 155 | // Header add header item string in request. 156 | func (r *Request) Header(key, value string) *Request { 157 | r.req.Header.Set(key, value) 158 | return r 159 | } 160 | 161 | func (r *Request) Headers() http.Header { 162 | return r.req.Header 163 | } 164 | 165 | // Set the protocol version for incoming requests. 166 | // Client requests always use HTTP/1.1. 167 | func (r *Request) SetProtocolVersion(vers string) *Request { 168 | if len(vers) == 0 { 169 | vers = "HTTP/1.1" 170 | } 171 | 172 | major, minor, ok := http.ParseHTTPVersion(vers) 173 | if ok { 174 | r.req.Proto = vers 175 | r.req.ProtoMajor = major 176 | r.req.ProtoMinor = minor 177 | } 178 | 179 | return r 180 | } 181 | 182 | // SetCookie add cookie into request. 183 | func (r *Request) SetCookie(cookie *http.Cookie) *Request { 184 | r.req.Header.Add("Cookie", cookie.String()) 185 | return r 186 | } 187 | 188 | // Set transport to 189 | func (r *Request) SetTransport(transport http.RoundTripper) *Request { 190 | r.setting.Transport = transport 191 | return r 192 | } 193 | 194 | // Set http proxy 195 | // example: 196 | // 197 | // func(req *http.Request) (*url.URL, error) { 198 | // u, _ := url.ParseRequestURI("http://127.0.0.1:8118") 199 | // return u, nil 200 | // } 201 | func (r *Request) SetProxy(proxy func(*http.Request) (*url.URL, error)) *Request { 202 | r.setting.Proxy = proxy 203 | return r 204 | } 205 | 206 | // Param adds query param in to request. 207 | // params build query string as ?key1=value1&key2=value2... 208 | func (r *Request) Param(key, value string) *Request { 209 | r.params[key] = value 210 | return r 211 | } 212 | 213 | func (r *Request) PostFile(formname, filename string) *Request { 214 | r.files[formname] = filename 215 | return r 216 | } 217 | 218 | // Body adds request raw body. 219 | // it supports string and []byte. 220 | func (r *Request) Body(data interface{}) *Request { 221 | switch t := data.(type) { 222 | case string: 223 | bf := bytes.NewBufferString(t) 224 | r.req.Body = ioutil.NopCloser(bf) 225 | r.req.ContentLength = int64(len(t)) 226 | case []byte: 227 | bf := bytes.NewBuffer(t) 228 | r.req.Body = ioutil.NopCloser(bf) 229 | r.req.ContentLength = int64(len(t)) 230 | } 231 | return r 232 | } 233 | 234 | func (r *Request) getResponse() (*http.Response, error) { 235 | if r.resp.StatusCode != 0 { 236 | return r.resp, nil 237 | } 238 | var paramBody string 239 | if len(r.params) > 0 { 240 | var buf bytes.Buffer 241 | for k, v := range r.params { 242 | buf.WriteString(url.QueryEscape(k)) 243 | buf.WriteByte('=') 244 | buf.WriteString(url.QueryEscape(v)) 245 | buf.WriteByte('&') 246 | } 247 | paramBody = buf.String() 248 | paramBody = paramBody[0 : len(paramBody)-1] 249 | } 250 | 251 | if r.req.Method == "GET" && len(paramBody) > 0 { 252 | if strings.Index(r.url, "?") != -1 { 253 | r.url += "&" + paramBody 254 | } else { 255 | r.url = r.url + "?" + paramBody 256 | } 257 | } else if r.req.Method == "POST" && r.req.Body == nil { 258 | if len(r.files) > 0 { 259 | pr, pw := io.Pipe() 260 | bodyWriter := multipart.NewWriter(pw) 261 | go func() { 262 | for formname, filename := range r.files { 263 | fileWriter, err := bodyWriter.CreateFormFile(formname, filename) 264 | if err != nil { 265 | log.Fatal(err) 266 | } 267 | fh, err := os.Open(filename) 268 | if err != nil { 269 | log.Fatal(err) 270 | } 271 | //iocopy 272 | _, err = io.Copy(fileWriter, fh) 273 | fh.Close() 274 | if err != nil { 275 | log.Fatal(err) 276 | } 277 | } 278 | for k, v := range r.params { 279 | bodyWriter.WriteField(k, v) 280 | } 281 | bodyWriter.Close() 282 | pw.Close() 283 | }() 284 | r.Header("Content-Type", bodyWriter.FormDataContentType()) 285 | r.req.Body = ioutil.NopCloser(pr) 286 | } else if len(paramBody) > 0 { 287 | r.Header("Content-Type", "application/x-www-form-urlencoded") 288 | r.Body(paramBody) 289 | } 290 | } 291 | 292 | url, err := url.Parse(r.url) 293 | if err != nil { 294 | return nil, err 295 | } 296 | 297 | r.req.URL = url 298 | 299 | trans := r.setting.Transport 300 | 301 | if trans == nil { 302 | // create default transport 303 | trans = &http.Transport{ 304 | TLSClientConfig: r.setting.TlsClientConfig, 305 | Proxy: r.setting.Proxy, 306 | Dial: TimeoutDialer(r.setting.ConnectTimeout, r.setting.ReadWriteTimeout), 307 | } 308 | } else { 309 | // if r.transport is *http.Transport then set the settings. 310 | if t, ok := trans.(*http.Transport); ok { 311 | if t.TLSClientConfig == nil { 312 | t.TLSClientConfig = r.setting.TlsClientConfig 313 | } 314 | if t.Proxy == nil { 315 | t.Proxy = r.setting.Proxy 316 | } 317 | if t.Dial == nil { 318 | t.Dial = TimeoutDialer(r.setting.ConnectTimeout, r.setting.ReadWriteTimeout) 319 | } 320 | } 321 | } 322 | 323 | var jar http.CookieJar 324 | if r.setting.EnableCookie { 325 | if defaultCookieJar == nil { 326 | createDefaultCookie() 327 | } 328 | jar = defaultCookieJar 329 | } else { 330 | jar = nil 331 | } 332 | 333 | client := &http.Client{ 334 | Transport: trans, 335 | Jar: jar, 336 | } 337 | 338 | if len(r.setting.UserAgent) > 0 && len(r.req.Header.Get("User-Agent")) == 0 { 339 | r.req.Header.Set("User-Agent", r.setting.UserAgent) 340 | } 341 | 342 | if r.setting.ShowDebug { 343 | dump, err := httputil.DumpRequest(r.req, true) 344 | if err != nil { 345 | println(err.Error()) 346 | } 347 | println(string(dump)) 348 | } 349 | 350 | resp, err := client.Do(r.req) 351 | if err != nil { 352 | return nil, err 353 | } 354 | r.resp = resp 355 | return resp, nil 356 | } 357 | 358 | // String returns the body string in response. 359 | // it calls Response inner. 360 | func (r *Request) String() (string, error) { 361 | data, err := r.Bytes() 362 | if err != nil { 363 | return "", err 364 | } 365 | 366 | return string(data), nil 367 | } 368 | 369 | // Bytes returns the body []byte in response. 370 | // it calls Response inner. 371 | func (r *Request) Bytes() ([]byte, error) { 372 | if r.body != nil { 373 | return r.body, nil 374 | } 375 | resp, err := r.getResponse() 376 | if err != nil { 377 | return nil, err 378 | } 379 | if resp.Body == nil { 380 | return nil, nil 381 | } 382 | defer resp.Body.Close() 383 | data, err := ioutil.ReadAll(resp.Body) 384 | if err != nil { 385 | return nil, err 386 | } 387 | r.body = data 388 | return data, nil 389 | } 390 | 391 | // ToFile saves the body data in response to one file. 392 | // it calls Response inner. 393 | func (r *Request) ToFile(filename string) error { 394 | f, err := os.Create(filename) 395 | if err != nil { 396 | return err 397 | } 398 | defer f.Close() 399 | 400 | resp, err := r.getResponse() 401 | if err != nil { 402 | return err 403 | } 404 | if resp.Body == nil { 405 | return nil 406 | } 407 | defer resp.Body.Close() 408 | _, err = io.Copy(f, resp.Body) 409 | return err 410 | } 411 | 412 | // ToJson returns the map that marshals from the body bytes as json in response . 413 | // it calls Response inner. 414 | func (r *Request) ToJson(v interface{}) error { 415 | data, err := r.Bytes() 416 | if err != nil { 417 | return err 418 | } 419 | err = json.Unmarshal(data, v) 420 | return err 421 | } 422 | 423 | // ToXml returns the map that marshals from the body bytes as xml in response . 424 | // it calls Response inner. 425 | func (r *Request) ToXml(v interface{}) error { 426 | data, err := r.Bytes() 427 | if err != nil { 428 | return err 429 | } 430 | err = xml.Unmarshal(data, v) 431 | return err 432 | } 433 | 434 | // Response executes request client gets response mannually. 435 | func (r *Request) Response() (*http.Response, error) { 436 | return r.getResponse() 437 | } 438 | 439 | // TimeoutDialer returns functions of connection dialer with timeout settings for http.Transport Dial field. 440 | func TimeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, addr string) (c net.Conn, err error) { 441 | return func(netw, addr string) (net.Conn, error) { 442 | conn, err := net.DialTimeout(netw, addr, cTimeout) 443 | if err != nil { 444 | return nil, err 445 | } 446 | conn.SetDeadline(time.Now().Add(rwTimeout)) 447 | return conn, nil 448 | } 449 | } 450 | -------------------------------------------------------------------------------- /vendor/httplib/httplib_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Beego Authors. All rights reserved. 2 | // Copyright 2014 The Gogs Authors. All rights reserved. 3 | // Use of this source code is governed by a MIT-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package httplib 7 | 8 | import ( 9 | "io/ioutil" 10 | "os" 11 | "strings" 12 | "testing" 13 | ) 14 | 15 | func TestResponse(t *testing.T) { 16 | req := Get("http://httpbin.org/get") 17 | resp, err := req.Response() 18 | if err != nil { 19 | t.Fatal(err) 20 | } 21 | t.Log(resp) 22 | } 23 | 24 | func TestGet(t *testing.T) { 25 | req := Get("http://httpbin.org/get") 26 | b, err := req.Bytes() 27 | if err != nil { 28 | t.Fatal(err) 29 | } 30 | t.Log(b) 31 | 32 | s, err := req.String() 33 | if err != nil { 34 | t.Fatal(err) 35 | } 36 | t.Log(s) 37 | 38 | if string(b) != s { 39 | t.Fatal("request data not match") 40 | } 41 | } 42 | 43 | func TestSimplePost(t *testing.T) { 44 | v := "smallfish" 45 | req := Post("http://httpbin.org/post") 46 | req.Param("username", v) 47 | 48 | str, err := req.String() 49 | if err != nil { 50 | t.Fatal(err) 51 | } 52 | t.Log(str) 53 | 54 | n := strings.Index(str, v) 55 | if n == -1 { 56 | t.Fatal(v + " not found in post") 57 | } 58 | } 59 | 60 | // func TestPostFile(t *testing.T) { 61 | // v := "smallfish" 62 | // req := Post("http://httpbin.org/post") 63 | // req.Param("username", v) 64 | // req.PostFile("uploadfile", "httplib_test.go") 65 | 66 | // str, err := req.String() 67 | // if err != nil { 68 | // t.Fatal(err) 69 | // } 70 | // t.Log(str) 71 | 72 | // n := strings.Index(str, v) 73 | // if n == -1 { 74 | // t.Fatal(v + " not found in post") 75 | // } 76 | // } 77 | 78 | func TestSimplePut(t *testing.T) { 79 | str, err := Put("http://httpbin.org/put").String() 80 | if err != nil { 81 | t.Fatal(err) 82 | } 83 | t.Log(str) 84 | } 85 | 86 | func TestSimpleDelete(t *testing.T) { 87 | str, err := Delete("http://httpbin.org/delete").String() 88 | if err != nil { 89 | t.Fatal(err) 90 | } 91 | t.Log(str) 92 | } 93 | 94 | func TestWithCookie(t *testing.T) { 95 | v := "smallfish" 96 | str, err := Get("http://httpbin.org/cookies/set?k1=" + v).SetEnableCookie(true).String() 97 | if err != nil { 98 | t.Fatal(err) 99 | } 100 | t.Log(str) 101 | 102 | str, err = Get("http://httpbin.org/cookies").SetEnableCookie(true).String() 103 | if err != nil { 104 | t.Fatal(err) 105 | } 106 | t.Log(str) 107 | 108 | n := strings.Index(str, v) 109 | if n == -1 { 110 | t.Fatal(v + " not found in cookie") 111 | } 112 | } 113 | 114 | func TestWithBasicAuth(t *testing.T) { 115 | str, err := Get("http://httpbin.org/basic-auth/handdler/passwd").SetBasicAuth("handdler", "passwd").String() 116 | if err != nil { 117 | t.Fatal(err) 118 | } 119 | t.Log(str) 120 | n := strings.Index(str, "authenticated") 121 | if n == -1 { 122 | t.Fatal("authenticated not found in response") 123 | } 124 | } 125 | 126 | func TestWithUserAgent(t *testing.T) { 127 | v := "beego" 128 | str, err := Get("http://httpbin.org/headers").SetUserAgent(v).String() 129 | if err != nil { 130 | t.Fatal(err) 131 | } 132 | t.Log(str) 133 | 134 | n := strings.Index(str, v) 135 | if n == -1 { 136 | t.Fatal(v + " not found in handdler-agent") 137 | } 138 | } 139 | 140 | func TestWithSetting(t *testing.T) { 141 | v := "beego" 142 | var setting BeegoHttpSettings 143 | setting.EnableCookie = true 144 | setting.UserAgent = v 145 | setting.Transport = nil 146 | SetDefaultSetting(setting) 147 | 148 | str, err := Get("http://httpbin.org/get").String() 149 | if err != nil { 150 | t.Fatal(err) 151 | } 152 | t.Log(str) 153 | 154 | n := strings.Index(str, v) 155 | if n == -1 { 156 | t.Fatal(v + " not found in handdler-agent") 157 | } 158 | } 159 | 160 | func TestToJson(t *testing.T) { 161 | req := Get("http://httpbin.org/ip") 162 | resp, err := req.Response() 163 | if err != nil { 164 | t.Fatal(err) 165 | } 166 | t.Log(resp) 167 | 168 | // httpbin will return http remote addr 169 | type Ip struct { 170 | Origin string `json:"origin"` 171 | } 172 | var ip Ip 173 | err = req.ToJson(&ip) 174 | if err != nil { 175 | t.Fatal(err) 176 | } 177 | t.Log(ip.Origin) 178 | 179 | if n := strings.Count(ip.Origin, "."); n != 3 { 180 | t.Fatal("response is not valid ip") 181 | } 182 | } 183 | 184 | func TestToFile(t *testing.T) { 185 | f := "beego_testfile" 186 | req := Get("http://httpbin.org/ip") 187 | err := req.ToFile(f) 188 | if err != nil { 189 | t.Fatal(err) 190 | } 191 | defer os.Remove(f) 192 | b, err := ioutil.ReadFile(f) 193 | if n := strings.Index(string(b), "origin"); n == -1 { 194 | t.Fatal(err) 195 | } 196 | } 197 | 198 | func TestHeader(t *testing.T) { 199 | req := Get("http://httpbin.org/headers") 200 | req.Header("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36") 201 | str, err := req.String() 202 | if err != nil { 203 | t.Fatal(err) 204 | } 205 | t.Log(str) 206 | } 207 | --------------------------------------------------------------------------------