...

Source file src/github.com/go-openapi/runtime/request.go

Documentation: github.com/go-openapi/runtime

     1  // Copyright 2015 go-swagger maintainers
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package runtime
    16  
    17  import (
    18  	"bufio"
    19  	"context"
    20  	"errors"
    21  	"io"
    22  	"net/http"
    23  	"strings"
    24  
    25  	"github.com/go-openapi/swag"
    26  )
    27  
    28  // CanHaveBody returns true if this method can have a body
    29  func CanHaveBody(method string) bool {
    30  	mn := strings.ToUpper(method)
    31  	return mn == "POST" || mn == "PUT" || mn == "PATCH" || mn == "DELETE"
    32  }
    33  
    34  // IsSafe returns true if this is a request with a safe method
    35  func IsSafe(r *http.Request) bool {
    36  	mn := strings.ToUpper(r.Method)
    37  	return mn == "GET" || mn == "HEAD"
    38  }
    39  
    40  // AllowsBody returns true if the request allows for a body
    41  func AllowsBody(r *http.Request) bool {
    42  	mn := strings.ToUpper(r.Method)
    43  	return mn != "HEAD"
    44  }
    45  
    46  // HasBody returns true if this method needs a content-type
    47  func HasBody(r *http.Request) bool {
    48  	// happy case: we have a content length set
    49  	if r.ContentLength > 0 {
    50  		return true
    51  	}
    52  
    53  	if r.Header.Get("content-length") != "" {
    54  		// in this case, no Transfer-Encoding should be present
    55  		// we have a header set but it was explicitly set to 0, so we assume no body
    56  		return false
    57  	}
    58  
    59  	rdr := newPeekingReader(r.Body)
    60  	r.Body = rdr
    61  	return rdr.HasContent()
    62  }
    63  
    64  func newPeekingReader(r io.ReadCloser) *peekingReader {
    65  	if r == nil {
    66  		return nil
    67  	}
    68  	return &peekingReader{
    69  		underlying: bufio.NewReader(r),
    70  		orig:       r,
    71  	}
    72  }
    73  
    74  type peekingReader struct {
    75  	underlying interface {
    76  		Buffered() int
    77  		Peek(int) ([]byte, error)
    78  		Read([]byte) (int, error)
    79  	}
    80  	orig io.ReadCloser
    81  }
    82  
    83  func (p *peekingReader) HasContent() bool {
    84  	if p == nil {
    85  		return false
    86  	}
    87  	if p.underlying.Buffered() > 0 {
    88  		return true
    89  	}
    90  	b, err := p.underlying.Peek(1)
    91  	if err != nil {
    92  		return false
    93  	}
    94  	return len(b) > 0
    95  }
    96  
    97  func (p *peekingReader) Read(d []byte) (int, error) {
    98  	if p == nil {
    99  		return 0, io.EOF
   100  	}
   101  	if p.underlying == nil {
   102  		return 0, io.ErrUnexpectedEOF
   103  	}
   104  	return p.underlying.Read(d)
   105  }
   106  
   107  func (p *peekingReader) Close() error {
   108  	if p.underlying == nil {
   109  		return errors.New("reader already closed")
   110  	}
   111  	p.underlying = nil
   112  	if p.orig != nil {
   113  		return p.orig.Close()
   114  	}
   115  	return nil
   116  }
   117  
   118  // JSONRequest creates a new http request with json headers set.
   119  //
   120  // It uses context.Background.
   121  func JSONRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
   122  	req, err := http.NewRequestWithContext(context.Background(), method, urlStr, body)
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  	req.Header.Add(HeaderContentType, JSONMime)
   127  	req.Header.Add(HeaderAccept, JSONMime)
   128  	return req, nil
   129  }
   130  
   131  // Gettable for things with a method GetOK(string) (data string, hasKey bool, hasValue bool)
   132  type Gettable interface {
   133  	GetOK(string) ([]string, bool, bool)
   134  }
   135  
   136  // ReadSingleValue reads a single value from the source
   137  func ReadSingleValue(values Gettable, name string) string {
   138  	vv, _, hv := values.GetOK(name)
   139  	if hv {
   140  		return vv[len(vv)-1]
   141  	}
   142  	return ""
   143  }
   144  
   145  // ReadCollectionValue reads a collection value from a string data source
   146  func ReadCollectionValue(values Gettable, name, collectionFormat string) []string {
   147  	v := ReadSingleValue(values, name)
   148  	return swag.SplitByFormat(v, collectionFormat)
   149  }
   150  

View as plain text