// WriteHeader is used to set the HTTP status code. func (s *ResponseStream) WriteHeader(code int) { if s.unidirectional { log.Println("Error: Stream is unidirectional.") return } if s.wroteHeader { log.Println("Error: Multiple calls to ResponseWriter.WriteHeader.") return } s.wroteHeader = true s.responseCode = code s.header.Set(":status", strconv.Itoa(code)) s.header.Set(":version", "HTTP/1.1") // Create the response SYN_REPLY. synReply := new(frames.SYN_REPLY) synReply.StreamID = s.streamID synReply.Header = make(http.Header) // Clear the headers that have been sent. for name, values := range s.header { for _, value := range values { synReply.Header.Add(name, value) } s.header.Del(name) } // These responses have no body, so close the stream now. if code == 204 || code == 304 || code/100 == 1 { synReply.Flags = common.FLAG_FIN s.state.CloseHere() } s.output <- synReply }
// run is the main control path of // the stream. It is prepared, the // registered handler is called, // and then the stream is cleaned // up and closed. func (s *ResponseStream) Run() error { // Catch any panics. defer func() { if v := recover(); v != nil { if s != nil && s.state != nil && !s.state.Closed() { log.Printf("Encountered stream error: %v (%[1]T)\n", v) } } }() // Make sure Request is prepared. if s.requestBody == nil || s.request.Body == nil { s.requestBody = new(bytes.Buffer) s.request.Body = &common.ReadCloser{s.requestBody} } // Wait until the full request has been received. <-s.ready /*************** *** HANDLER *** ***************/ s.handler.ServeHTTP(s, s.request) // Make sure any queued data has been sent. if err := s.flow.Wait(); err != nil { log.Println(err) } // Close the stream with a SYN_REPLY if // none has been sent, or an empty DATA // frame, if a SYN_REPLY has been sent // already. // If the stream is already closed at // this end, then nothing happens. if !s.unidirectional { if s.state.OpenHere() && !s.wroteHeader { s.header.Set(":status", "200") s.header.Set(":version", "HTTP/1.1") // Create the response SYN_REPLY. synReply := new(frames.SYN_REPLY) synReply.Flags = common.FLAG_FIN synReply.StreamID = s.streamID synReply.Header = make(http.Header) for name, values := range s.header { for _, value := range values { synReply.Header.Add(name, value) } s.header.Del(name) } s.output <- synReply } else if s.state.OpenHere() { // Create the DATA. data := new(frames.DATA) data.StreamID = s.streamID data.Flags = common.FLAG_FIN data.Data = []byte{} s.output <- data } } // Clean up state. s.state.CloseHere() if s.state.Closed() { return s.Close() } return nil }