serveLongPoll handles long poll connections when WebSocket is not available Connection could be without sid or with sid: - if sid is empty, create session, expect a login in the same request, respond and close - if sid is not empty and there is an initialized session, payload is optional - if no pay
(wrt http.ResponseWriter, req *http.Request)
| 122 | // - if payload exists, process it and close |
| 123 | // - if sid is not empty but there is no session, report an error |
| 124 | func serveLongPoll(wrt http.ResponseWriter, req *http.Request) { |
| 125 | now := time.Now().UTC().Round(time.Millisecond) |
| 126 | |
| 127 | // Use the lowest common denominator - this is a legacy handler after all (otherwise would use application/json) |
| 128 | wrt.Header().Set("Content-Type", "text/plain") |
| 129 | if globals.tlsStrictMaxAge != "" { |
| 130 | wrt.Header().Set("Strict-Transport-Security", "max-age"+globals.tlsStrictMaxAge) |
| 131 | } |
| 132 | |
| 133 | enc := json.NewEncoder(wrt) |
| 134 | |
| 135 | if isValid, _ := checkAPIKey(getAPIKey(req)); !isValid { |
| 136 | wrt.WriteHeader(http.StatusForbidden) |
| 137 | enc.Encode(ErrAPIKeyRequired(now)) |
| 138 | return |
| 139 | } |
| 140 | |
| 141 | // TODO(gene): should it be configurable? |
| 142 | // Currently any domain is allowed to get data from the chat server |
| 143 | wrt.Header().Set("Access-Control-Allow-Origin", "*") |
| 144 | |
| 145 | // Ensure the response is not cached |
| 146 | if req.ProtoAtLeast(1, 1) { |
| 147 | wrt.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") // HTTP 1.1 |
| 148 | } else { |
| 149 | wrt.Header().Set("Pragma", "no-cache") // HTTP 1.0 |
| 150 | } |
| 151 | wrt.Header().Set("Expires", "0") // Proxies |
| 152 | |
| 153 | // TODO(gene): respond differently to valious HTTP methods |
| 154 | |
| 155 | // Get session id |
| 156 | sid := req.FormValue("sid") |
| 157 | var sess *Session |
| 158 | if sid == "" { |
| 159 | // New session |
| 160 | var count int |
| 161 | sess, count = globals.sessionStore.NewSession(wrt, "") |
| 162 | sess.remoteAddr = getRemoteAddr(req) |
| 163 | logs.Info.Println("longPoll: session started", sess.sid, sess.remoteAddr, count) |
| 164 | |
| 165 | wrt.WriteHeader(http.StatusCreated) |
| 166 | pkt := NoErrCreated(req.FormValue("id"), "", now) |
| 167 | pkt.Ctrl.Params = map[string]string{ |
| 168 | "sid": sess.sid, |
| 169 | } |
| 170 | enc.Encode(pkt) |
| 171 | |
| 172 | return |
| 173 | } |
| 174 | |
| 175 | // Existing session |
| 176 | sess = globals.sessionStore.Get(sid) |
| 177 | if sess == nil { |
| 178 | logs.Warn.Println("longPoll: invalid or expired session id", sid) |
| 179 | wrt.WriteHeader(http.StatusForbidden) |
| 180 | enc.Encode(ErrSessionNotFound(now)) |
| 181 | return |
nothing calls this directly
no test coverage detected
searching dependent graphs…