http_client.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. package thrift
  20. import (
  21. "bytes"
  22. "io"
  23. "net/http"
  24. "net/url"
  25. "strconv"
  26. )
  27. type THttpClient struct {
  28. response *http.Response
  29. url *url.URL
  30. requestBuffer *bytes.Buffer
  31. header http.Header
  32. nsecConnectTimeout int64
  33. nsecReadTimeout int64
  34. }
  35. type THttpClientTransportFactory struct {
  36. url string
  37. isPost bool
  38. }
  39. func (p *THttpClientTransportFactory) GetTransport(trans TTransport) TTransport {
  40. if trans != nil {
  41. t, ok := trans.(*THttpClient)
  42. if ok && t.url != nil {
  43. if t.requestBuffer != nil {
  44. t2, _ := NewTHttpPostClient(t.url.String())
  45. return t2
  46. }
  47. t2, _ := NewTHttpClient(t.url.String())
  48. return t2
  49. }
  50. }
  51. if p.isPost {
  52. s, _ := NewTHttpPostClient(p.url)
  53. return s
  54. }
  55. s, _ := NewTHttpClient(p.url)
  56. return s
  57. }
  58. func NewTHttpClientTransportFactory(url string) *THttpClientTransportFactory {
  59. return &THttpClientTransportFactory{url: url, isPost: false}
  60. }
  61. func NewTHttpPostClientTransportFactory(url string) *THttpClientTransportFactory {
  62. return &THttpClientTransportFactory{url: url, isPost: true}
  63. }
  64. func NewTHttpClient(urlstr string) (TTransport, error) {
  65. parsedURL, err := url.Parse(urlstr)
  66. if err != nil {
  67. return nil, err
  68. }
  69. response, err := http.Get(urlstr)
  70. if err != nil {
  71. return nil, err
  72. }
  73. return &THttpClient{response: response, url: parsedURL}, nil
  74. }
  75. func NewTHttpPostClient(urlstr string) (TTransport, error) {
  76. parsedURL, err := url.Parse(urlstr)
  77. if err != nil {
  78. return nil, err
  79. }
  80. buf := make([]byte, 0, 1024)
  81. return &THttpClient{url: parsedURL, requestBuffer: bytes.NewBuffer(buf), header: http.Header{}}, nil
  82. }
  83. // Set the HTTP Header for this specific Thrift Transport
  84. // It is important that you first assert the TTransport as a THttpClient type
  85. // like so:
  86. //
  87. // httpTrans := trans.(THttpClient)
  88. // httpTrans.SetHeader("User-Agent","Thrift Client 1.0")
  89. func (p *THttpClient) SetHeader(key string, value string) {
  90. p.header.Add(key, value)
  91. }
  92. // Get the HTTP Header represented by the supplied Header Key for this specific Thrift Transport
  93. // It is important that you first assert the TTransport as a THttpClient type
  94. // like so:
  95. //
  96. // httpTrans := trans.(THttpClient)
  97. // hdrValue := httpTrans.GetHeader("User-Agent")
  98. func (p *THttpClient) GetHeader(key string) string {
  99. return p.header.Get(key)
  100. }
  101. // Deletes the HTTP Header given a Header Key for this specific Thrift Transport
  102. // It is important that you first assert the TTransport as a THttpClient type
  103. // like so:
  104. //
  105. // httpTrans := trans.(THttpClient)
  106. // httpTrans.DelHeader("User-Agent")
  107. func (p *THttpClient) DelHeader(key string) {
  108. p.header.Del(key)
  109. }
  110. func (p *THttpClient) Open() error {
  111. // do nothing
  112. return nil
  113. }
  114. func (p *THttpClient) IsOpen() bool {
  115. return p.response != nil || p.requestBuffer != nil
  116. }
  117. func (p *THttpClient) Peek() bool {
  118. return p.IsOpen()
  119. }
  120. func (p *THttpClient) Close() error {
  121. if p.response != nil && p.response.Body != nil {
  122. err := p.response.Body.Close()
  123. p.response = nil
  124. return err
  125. }
  126. if p.requestBuffer != nil {
  127. p.requestBuffer.Reset()
  128. p.requestBuffer = nil
  129. }
  130. return nil
  131. }
  132. func (p *THttpClient) Read(buf []byte) (int, error) {
  133. if p.response == nil {
  134. return 0, NewTTransportException(NOT_OPEN, "Response buffer is empty, no request.")
  135. }
  136. n, err := p.response.Body.Read(buf)
  137. if n > 0 && (err == nil || err == io.EOF) {
  138. return n, nil
  139. }
  140. return n, NewTTransportExceptionFromError(err)
  141. }
  142. func (p *THttpClient) ReadByte() (c byte, err error) {
  143. return readByte(p.response.Body)
  144. }
  145. func (p *THttpClient) Write(buf []byte) (int, error) {
  146. n, err := p.requestBuffer.Write(buf)
  147. return n, err
  148. }
  149. func (p *THttpClient) WriteByte(c byte) error {
  150. return p.requestBuffer.WriteByte(c)
  151. }
  152. func (p *THttpClient) WriteString(s string) (n int, err error) {
  153. return p.requestBuffer.WriteString(s)
  154. }
  155. func (p *THttpClient) Flush() error {
  156. client := &http.Client{}
  157. req, err := http.NewRequest("POST", p.url.String(), p.requestBuffer)
  158. if err != nil {
  159. return NewTTransportExceptionFromError(err)
  160. }
  161. p.header.Add("Content-Type", "application/x-thrift")
  162. req.Header = p.header
  163. response, err := client.Do(req)
  164. if err != nil {
  165. return NewTTransportExceptionFromError(err)
  166. }
  167. if response.StatusCode != http.StatusOK {
  168. // TODO(pomack) log bad response
  169. return NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "HTTP Response code: "+strconv.Itoa(response.StatusCode))
  170. }
  171. p.response = response
  172. return nil
  173. }