github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/igm/sockjs-go.v2/sockjs/options.go (about)

     1  package sockjs
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"math/rand"
     7  	"net/http"
     8  	"sync"
     9  	"time"
    10  )
    11  
    12  var (
    13  	entropy      *rand.Rand
    14  	entropyMutex sync.Mutex
    15  )
    16  
    17  func init() {
    18  	entropy = rand.New(rand.NewSource(time.Now().UnixNano()))
    19  }
    20  
    21  // Options type is used for defining various sockjs options
    22  type Options struct {
    23  	// Transports which don't support cross-domain communication natively ('eventsource' to name one) use an iframe trick.
    24  	// A simple page is served from the SockJS server (using its foreign domain) and is placed in an invisible iframe.
    25  	// Code run from this iframe doesn't need to worry about cross-domain issues, as it's being run from domain local to the SockJS server.
    26  	// This iframe also does need to load SockJS javascript client library, and this option lets you specify its url (if you're unsure,
    27  	// point it to the latest minified SockJS client release, this is the default). You must explicitly specify this url on the server
    28  	// side for security reasons - we don't want the possibility of running any foreign javascript within the SockJS domain (aka cross site scripting attack).
    29  	// Also, sockjs javascript library is probably already cached by the browser - it makes sense to reuse the sockjs url you're using in normally.
    30  	SockJSURL string
    31  	// Most streaming transports save responses on the client side and don't free memory used by delivered messages.
    32  	// Such transports need to be garbage-collected once in a while. `response_limit` sets a minimum number of bytes that can be send
    33  	// over a single http streaming request before it will be closed. After that client needs to open new request.
    34  	// Setting this value to one effectively disables streaming and will make streaming transports to behave like polling transports.
    35  	// The default value is 128K.
    36  	ResponseLimit uint32
    37  	// Some load balancers don't support websockets. This option can be used to disable websockets support by the server. By default websockets are enabled.
    38  	Websocket bool
    39  	// In order to keep proxies and load balancers from closing long running http requests we need to pretend that the connection is active
    40  	// and send a heartbeat packet once in a while. This setting controls how often this is done.
    41  	// By default a heartbeat packet is sent every 25 seconds.
    42  	HeartbeatDelay time.Duration
    43  	// The server closes a session when a client receiving connection have not been seen for a while.
    44  	// This delay is configured by this setting.
    45  	// By default the session is closed when a receiving connection wasn't seen for 5 seconds.
    46  	DisconnectDelay time.Duration
    47  	// Some hosting providers enable sticky sessions only to requests that have JSessionID cookie set.
    48  	// This setting controls if the server should set this cookie to a dummy value.
    49  	// By default setting JSessionID cookie is disabled. More sophisticated behaviour can be achieved by supplying a function.
    50  	JSessionID func(http.ResponseWriter, *http.Request)
    51  }
    52  
    53  // DefaultOptions is a convenient set of options to be used for sockjs
    54  var DefaultOptions = Options{
    55  	Websocket:       true,
    56  	JSessionID:      nil,
    57  	SockJSURL:       "/libs/sockjsCli/sockjs.min.js",
    58  	HeartbeatDelay:  25 * time.Second,
    59  	DisconnectDelay: 5 * time.Second,
    60  	ResponseLimit:   128 * 1024,
    61  }
    62  
    63  type info struct {
    64  	Websocket    bool     `json:"websocket"`
    65  	CookieNeeded bool     `json:"cookie_needed"`
    66  	Origins      []string `json:"origins"`
    67  	Entropy      int32    `json:"entropy"`
    68  }
    69  
    70  func (options *Options) info(rw http.ResponseWriter, req *http.Request) {
    71  	switch req.Method {
    72  	case "GET":
    73  		rw.Header().Set("Content-Type", "application/json; charset=UTF-8")
    74  		json.NewEncoder(rw).Encode(info{
    75  			Websocket:    options.Websocket,
    76  			CookieNeeded: options.JSessionID != nil,
    77  			Origins:      []string{"*:*"},
    78  			Entropy:      generateEntropy(),
    79  		})
    80  	case "OPTIONS":
    81  		rw.Header().Set("Access-Control-Allow-Methods", "OPTIONS, GET")
    82  		rw.Header().Set("Access-Control-Max-Age", fmt.Sprintf("%d", 365*24*60*60))
    83  		rw.WriteHeader(http.StatusNoContent) // 204
    84  	default:
    85  		http.NotFound(rw, req)
    86  	}
    87  }
    88  
    89  // DefaultJSessionID is a default behaviour function to be used in options for JSessionID if JSESSIONID is needed
    90  func DefaultJSessionID(rw http.ResponseWriter, req *http.Request) {
    91  	cookie, err := req.Cookie("JSESSIONID")
    92  	if err == http.ErrNoCookie {
    93  		cookie = &http.Cookie{
    94  			Name:  "JSESSIONID",
    95  			Value: "dummy",
    96  		}
    97  	}
    98  	cookie.Path = "/"
    99  	header := rw.Header()
   100  	header.Add("Set-Cookie", cookie.String())
   101  }
   102  
   103  func (options *Options) cookie(rw http.ResponseWriter, req *http.Request) {
   104  	if options.JSessionID != nil { // cookie is needed
   105  		options.JSessionID(rw, req)
   106  	}
   107  }
   108  
   109  func generateEntropy() int32 {
   110  	entropyMutex.Lock()
   111  	entropy := entropy.Int31()
   112  	entropyMutex.Unlock()
   113  	return entropy
   114  }