<commit_before>package store

import (
	"encoding/json"
	"io"
	"launchpad.net/juju-core/charm"
	"launchpad.net/juju-core/log"
	"net/http"
	"strconv"
	"strings"
)

// Server is an http.Handler that serves the HTTP API of juju
// so that juju clients can retrieve published charms.
type Server struct {
	store *Store
	mux   *http.ServeMux
}

// New returns a new *Server using store.
func NewServer(store *Store) (*Server, error) {
	s := &Server{
		store: store,
		mux:   http.NewServeMux(),
	}
	s.mux.HandleFunc("/charm-info", func(w http.ResponseWriter, r *http.Request) {
		s.serveInfo(w, r)
	})
	s.mux.HandleFunc("/charm/", func(w http.ResponseWriter, r *http.Request) {
		s.serveCharm(w, r)
	})
	s.mux.HandleFunc("/stats/counter/", func(w http.ResponseWriter, r *http.Request) {
		s.serveStats(w, r)
	})

	// This is just a validation key to allow blitz.io to run
	// performance tests against the site.
	s.mux.HandleFunc("/mu-35700a31-6bf320ca-a800b670-05f845ee", func(w http.ResponseWriter, r *http.Request) {
		s.serveBlitzKey(w, r)
	})
	return s, nil
}

// ServeHTTP serves an http request.
// This method turns *Server into an http.Handler.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" {
		http.Redirect(w, r, "https://juju.ubuntu.com", http.StatusSeeOther)
		return
	}
	s.mux.ServeHTTP(w, r)
}

func statsEnabled(req *http.Request) bool {
	// It's fine to parse the form more than once, and it avoids
	// bugs from not parsing it.
	req.ParseForm()
	return req.Form.Get("stats") != "0"
}

func charmStatsKey(curl *charm.URL, kind string) []string {
	if curl.User == "" {
		return []string{kind, curl.Series, curl.Name}
	}
	return []string{kind, curl.Series, curl.Name, curl.User}
}

func (s *Server) serveInfo(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/charm-info" {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	r.ParseForm()
	response := map[string]*charm.InfoResponse{}
	for _, url := range r.Form["charms"] {
		c := &charm.InfoResponse{}
		response[url] = c
		curl, err := charm.ParseURL(url)
		var info *CharmInfo
		if err == nil {
			info, err = s.store.CharmInfo(curl)
		}
		var skey []string
		if err == nil {
			skey = charmStatsKey(curl, "charm-info")
			c.Sha256 = info.BundleSha256()
			c.Revision = info.Revision()
		} else {
			if err == ErrNotFound {
				skey = charmStatsKey(curl, "charm-missing")
			}
			c.Errors = append(c.Errors, err.Error())
		}
		if skey != nil && statsEnabled(r) {
			go s.store.IncCounter(skey)
		}
	}
	data, err := json.Marshal(response)
	if err == nil {
		w.Header().Set("Content-Type", "application/json")
		_, err = w.Write(data)
	}
	if err != nil {
		log.Printf("can't write content: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
}

func (s *Server) serveCharm(w http.ResponseWriter, r *http.Request) {
	if !strings.HasPrefix(r.URL.Path, "/charm/") {
		panic("serveCharm: bad url")
	}
	curl, err := charm.ParseURL("cs:" + r.URL.Path[len("/charm/"):])
	if err != nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	info, rc, err := s.store.OpenCharm(curl)
	if err == ErrNotFound {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Printf("can't open charm %q: %v", curl, err)
		return
	}
	if statsEnabled(r) {
		go s.store.IncCounter(charmStatsKey(curl, "charm-bundle"))
	}
	defer rc.Close()
	w.Header().Set("Connection", "close") // No keep-alive for now.
	w.Header().Set("Content-Type", "application/octet-stream")
	w.Header().Set("Content-Length", strconv.FormatInt(info.BundleSize(), 10))
	_, err = io.Copy(w, rc)
	if err != nil {
		log.Printf("failed to stream charm %q: %v", curl, err)
	}
}

func (s *Server) serveStats(w http.ResponseWriter, r *http.Request) {
	// TODO: Adopt a smarter mux that simplifies this logic.
	const dir = "/stats/counter/"
	if !strings.HasPrefix(r.URL.Path, dir) {
		panic("bad url")
	}
	base := r.URL.Path[len(dir):]
	if strings.Index(base, "/") > 0 {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	if base == "" {
		w.WriteHeader(http.StatusForbidden)
		return
	}
	key := strings.Split(base, ":")
	prefix := false
	if key[len(key)-1] == "*" {
		prefix = true
		key = key[:len(key)-1]
		if len(key) == 0 {
			// No point in counting something unknown.
			w.WriteHeader(http.StatusForbidden)
			return
		}
	}
	r.ParseForm()
	sum, err := s.store.SumCounter(key, prefix)
	if err != nil {
		log.Printf("can't sum counter: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	data := []byte(strconv.FormatInt(sum, 10))
	w.Header().Set("Content-Type", "text/plain")
	w.Header().Set("Content-Length", strconv.Itoa(len(data)))
	_, err = w.Write(data)
	if err != nil {
		log.Printf("can't write content: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
	}
}

func (s *Server) serveBlitzKey(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Connection", "close")
	w.Header().Set("Content-Type", "text/plain")
	w.Header().Set("Content-Length", "2")
	w.Write([]byte("42"))
}
<commit_msg>can't -> cannot<commit_after>package store

import (
	"encoding/json"
	"io"
	"launchpad.net/juju-core/charm"
	"launchpad.net/juju-core/log"
	"net/http"
	"strconv"
	"strings"
)

// Server is an http.Handler that serves the HTTP API of juju
// so that juju clients can retrieve published charms.
type Server struct {
	store *Store
	mux   *http.ServeMux
}

// New returns a new *Server using store.
func NewServer(store *Store) (*Server, error) {
	s := &Server{
		store: store,
		mux:   http.NewServeMux(),
	}
	s.mux.HandleFunc("/charm-info", func(w http.ResponseWriter, r *http.Request) {
		s.serveInfo(w, r)
	})
	s.mux.HandleFunc("/charm/", func(w http.ResponseWriter, r *http.Request) {
		s.serveCharm(w, r)
	})
	s.mux.HandleFunc("/stats/counter/", func(w http.ResponseWriter, r *http.Request) {
		s.serveStats(w, r)
	})

	// This is just a validation key to allow blitz.io to run
	// performance tests against the site.
	s.mux.HandleFunc("/mu-35700a31-6bf320ca-a800b670-05f845ee", func(w http.ResponseWriter, r *http.Request) {
		s.serveBlitzKey(w, r)
	})
	return s, nil
}

// ServeHTTP serves an http request.
// This method turns *Server into an http.Handler.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" {
		http.Redirect(w, r, "https://juju.ubuntu.com", http.StatusSeeOther)
		return
	}
	s.mux.ServeHTTP(w, r)
}

func statsEnabled(req *http.Request) bool {
	// It's fine to parse the form more than once, and it avoids
	// bugs from not parsing it.
	req.ParseForm()
	return req.Form.Get("stats") != "0"
}

func charmStatsKey(curl *charm.URL, kind string) []string {
	if curl.User == "" {
		return []string{kind, curl.Series, curl.Name}
	}
	return []string{kind, curl.Series, curl.Name, curl.User}
}

func (s *Server) serveInfo(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/charm-info" {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	r.ParseForm()
	response := map[string]*charm.InfoResponse{}
	for _, url := range r.Form["charms"] {
		c := &charm.InfoResponse{}
		response[url] = c
		curl, err := charm.ParseURL(url)
		var info *CharmInfo
		if err == nil {
			info, err = s.store.CharmInfo(curl)
		}
		var skey []string
		if err == nil {
			skey = charmStatsKey(curl, "charm-info")
			c.Sha256 = info.BundleSha256()
			c.Revision = info.Revision()
		} else {
			if err == ErrNotFound {
				skey = charmStatsKey(curl, "charm-missing")
			}
			c.Errors = append(c.Errors, err.Error())
		}
		if skey != nil && statsEnabled(r) {
			go s.store.IncCounter(skey)
		}
	}
	data, err := json.Marshal(response)
	if err == nil {
		w.Header().Set("Content-Type", "application/json")
		_, err = w.Write(data)
	}
	if err != nil {
		log.Printf("cannot write content: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
}

func (s *Server) serveCharm(w http.ResponseWriter, r *http.Request) {
	if !strings.HasPrefix(r.URL.Path, "/charm/") {
		panic("serveCharm: bad url")
	}
	curl, err := charm.ParseURL("cs:" + r.URL.Path[len("/charm/"):])
	if err != nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	info, rc, err := s.store.OpenCharm(curl)
	if err == ErrNotFound {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Printf("cannot open charm %q: %v", curl, err)
		return
	}
	if statsEnabled(r) {
		go s.store.IncCounter(charmStatsKey(curl, "charm-bundle"))
	}
	defer rc.Close()
	w.Header().Set("Connection", "close") // No keep-alive for now.
	w.Header().Set("Content-Type", "application/octet-stream")
	w.Header().Set("Content-Length", strconv.FormatInt(info.BundleSize(), 10))
	_, err = io.Copy(w, rc)
	if err != nil {
		log.Printf("failed to stream charm %q: %v", curl, err)
	}
}

func (s *Server) serveStats(w http.ResponseWriter, r *http.Request) {
	// TODO: Adopt a smarter mux that simplifies this logic.
	const dir = "/stats/counter/"
	if !strings.HasPrefix(r.URL.Path, dir) {
		panic("bad url")
	}
	base := r.URL.Path[len(dir):]
	if strings.Index(base, "/") > 0 {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	if base == "" {
		w.WriteHeader(http.StatusForbidden)
		return
	}
	key := strings.Split(base, ":")
	prefix := false
	if key[len(key)-1] == "*" {
		prefix = true
		key = key[:len(key)-1]
		if len(key) == 0 {
			// No point in counting something unknown.
			w.WriteHeader(http.StatusForbidden)
			return
		}
	}
	r.ParseForm()
	sum, err := s.store.SumCounter(key, prefix)
	if err != nil {
		log.Printf("cannot sum counter: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	data := []byte(strconv.FormatInt(sum, 10))
	w.Header().Set("Content-Type", "text/plain")
	w.Header().Set("Content-Length", strconv.Itoa(len(data)))
	_, err = w.Write(data)
	if err != nil {
		log.Printf("cannot write content: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
	}
}

func (s *Server) serveBlitzKey(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Connection", "close")
	w.Header().Set("Content-Type", "text/plain")
	w.Header().Set("Content-Length", "2")
	w.Write([]byte("42"))
}
<|endoftext|>


<commit_before>// spdy/server.go

package spdy

import (
	"bytes"
	"crypto/rand"
	"crypto/tls"
	"encoding/binary"
	"errors"
	"io"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

// ListenAndServe creates a new Server that serves on the given address.  If
// the handler is nil, then http.DefaultServeMux is used.
func ListenAndServe(addr string, handler http.Handler) error {
	srv := &Server{addr, handler}
	return srv.ListenAndServe()
}

// ListenAndServeTLS acts like ListenAndServe except it uses TLS.
func ListenAndServeTLS(addr string, certFile, keyFile string, handler http.Handler) (err error) {
	config := &tls.Config{
		Rand:         rand.Reader,
		Time:         time.Now,
		NextProtos:   []string{"spdy/2", "http/1.1"},
		Certificates: make([]tls.Certificate, 1),
	}
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return
	}

	conn, err := net.Listen("tcp", addr)
	if err != nil {
		return
	}
	tlsListener := tls.NewListener(conn, config)
	return (&Server{addr, handler}).Serve(tlsListener)
}

// A Server handles incoming SPDY connections with HTTP handlers.
type Server struct {
	Addr    string
	Handler http.Handler
}

// ListenAndServe services SPDY requests on the given address.
// If the handler is nil, then http.DefaultServeMux is used.
func (srv *Server) ListenAndServe() error {
	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}
	l, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return srv.Serve(l)
}

// ListenAndServe services SPDY requests using the given listener.
// If the handler is nil, then http.DefaultServeMux is used.
func (srv *Server) Serve(l net.Listener) error {
	defer l.Close()
	handler := srv.Handler
	if handler == nil {
		handler = http.DefaultServeMux
	}
	for {
		c, err := l.Accept()
		if err != nil {
			return err
		}
		s, err := newSession(c, handler)
		if err != nil {
			return err
		}
		go s.serve()
	}
	return nil
}

// A session manages a single TCP connection to a client.
type session struct {
	c         net.Conn
	handler   http.Handler
	out       chan Frame
	streams   map[uint32]*serverStream // all access is done synchronously
	last_good uint32

	headerReader *HeaderReader
	headerWriter *HeaderWriter
}

func newSession(c net.Conn, h http.Handler) (s *session, err error) {
	s = &session{
		c:            c,
		handler:      h,
		headerReader: NewHeaderReader(),
		headerWriter: NewHeaderWriter(-1),
		out:          make(chan Frame),
		streams:      make(map[uint32]*serverStream),
		last_good:    0,
	}
	return
}

func (sess *session) serve() {
	defer sess.c.Close()
	go sess.receiveFrames()

	for frame := range sess.out {

		if frame == nil {
			// EOF, signalling end of session
			// initiated by us (on errors, etc.)
			return
		}

		// TODO: Check for errors
		frame.WriteTo(sess.c)
	}
}

func (sess *session) fail() {
	sess.out <- ControlFrame{
		Type: TypeGoaway,
		Data: []byte{
			byte(sess.last_good & 0x7f000000 >> 24),
			byte(sess.last_good & 0x00ff0000 >> 16),
			byte(sess.last_good & 0x0000ff00 >> 8),
			byte(sess.last_good & 0x000000ff >> 0),
		},
	}
	sess.out <- nil
}

func (sess *session) handleControl(frame ControlFrame) {
	switch frame.Type {
	case TypeSynStream:
		if stream, err := newServerStream(sess, frame); err == nil {
			if _, exists := sess.streams[stream.id]; !exists {
				sess.streams[stream.id] = stream
				sess.last_good = stream.id
				go func() {
					sess.handler.ServeHTTP(stream, stream.Request())
					stream.finish()
				}()
			}
		}
	case TypeRstStream:
		d := bytes.NewBuffer(frame.Data)
		var streamId, statusCode uint32
		readBinary(d, &streamId, &statusCode)
	case TypePing:
		d := bytes.NewBuffer(frame.Data)
		var pingId uint32
		readBinary(d, &pingId)
		sess.out <- ControlFrame{
			Type: TypePing,
			Data: []byte{
				byte(pingId & 0xff000000 >> 24),
				byte(pingId & 0x00ff0000 >> 16),
				byte(pingId & 0x0000ff00 >> 8),
				byte(pingId & 0x000000ff >> 0),
			},
		}
	}
}

func (sess *session) handleData(frame DataFrame) {
	st, found := sess.streams[frame.StreamID]
	if !found {
		// TODO: Error?
		return
	}
	if st.dataPipe != nil {
		st.dataPipe.write(frame.Data)
		if frame.Flags&FlagFin != 0 {
			st.dataPipe.wclose(nil)
		}
	}
}

func (sess *session) receiveFrames() {
	for {
		f, err := ReadFrame(sess.c)
		if err != nil {
			return
		}

		if f == nil {
			// EOF, signalling end of session
			return
		}
		switch frame := f.(type) {
		case ControlFrame:
			sess.handleControl(frame)
		case DataFrame:
			sess.handleData(frame)
		}
	}
}

// A serverStream is a logical data stream inside a session.  A serverStream
// services a single request.
type serverStream struct {
	id      uint32
	session *session
	closed  bool

	requestHeaders  http.Header
	responseHeaders http.Header
	wroteHeader     bool

	dataPipe *asyncPipe
}

func newServerStream(sess *session, frame ControlFrame) (st *serverStream, err error) {
	if frame.Type != TypeSynStream {
		err = errors.New("Server stream must be created from a SynStream frame")
		return
	}
	st = &serverStream{
		session:         sess,
		responseHeaders: make(http.Header),
	}
	if frame.Flags&FlagFin == 0 {
		// Request body will follow
		st.dataPipe = apipe()
	}
	// Read frame data
	data := bytes.NewBuffer(frame.Data)
	err = binary.Read(data, binary.BigEndian, &st.id)
	if err != nil {
		return
	}
	_, err = io.ReadFull(data, make([]byte, 6)) // skip associated stream ID and priority
	if err != nil {
		return
	}
	st.requestHeaders, err = sess.headerReader.Decode(data.Bytes())
	return
}

// Request returns the request data associated with the serverStream.
func (st *serverStream) Request() (req *http.Request) {
	// TODO: Add more info
	req = &http.Request{
		Method:     st.requestHeaders.Get("method"),
		Proto:      st.requestHeaders.Get("version"),
		Header:     st.requestHeaders,
		Body:       st,
		RemoteAddr: st.session.c.RemoteAddr().String(),
	}
	req.URL, _ = url.ParseRequestURI(st.requestHeaders.Get("url"))
	return
}

func (st *serverStream) Read(p []byte) (n int, err error) {
	return st.dataPipe.read(p)
}

// Header returns the current response headers.
func (st *serverStream) Header() http.Header { return st.responseHeaders }

func (st *serverStream) Write(p []byte) (n int, err error) {
	if st.closed {
		err = errors.New("Write on closed serverStream")
		return
	}
	if !st.wroteHeader {
		st.WriteHeader(http.StatusOK)
	}
	for len(p) > 0 {
		frame := DataFrame{
			StreamID: st.id,
		}
		if len(p) < MaxDataLength {
			frame.Data = make([]byte, len(p))
		} else {
			frame.Data = make([]byte, MaxDataLength)
		}
		copy(frame.Data, p)
		p = p[len(frame.Data):]
		st.session.out <- frame
		n += len(frame.Data)
	}
	return
}

// A synReplyFrame defers header compression until the server writes the frame.
// This is necessary to guarantee correctly ordered compression.
type synReplyFrame struct {
	stream *serverStream
	header http.Header
	flags  FrameFlags
}

func (frame synReplyFrame) GetFlags() FrameFlags {
	return frame.flags
}

func (frame synReplyFrame) GetData() []byte {
	buf := new(bytes.Buffer)
	binary.Write(buf, binary.BigEndian, frame.stream.id&0x7fffffff)
	buf.Write([]byte{0, 0})
	frame.stream.session.headerWriter.WriteHeader(buf, frame.stream.responseHeaders)
	return buf.Bytes()
}

func (frame synReplyFrame) WriteTo(w io.Writer) (n int64, err error) {
	cf := ControlFrame{Type: TypeSynReply, Data: frame.GetData()}
	return cf.WriteTo(w)
}

func (st *serverStream) WriteHeader(code int) {
	if st.wroteHeader {
		return
	}
	st.responseHeaders.Set("status", strconv.Itoa(code)+" "+http.StatusText(code))
	st.responseHeaders.Set("version", "HTTP/1.1")
	if st.responseHeaders.Get("Content-Type") == "" {
		st.responseHeaders.Set("Content-Type", "text/html; charset=utf-8")
	}
	if st.responseHeaders.Get("Date") == "" {
		st.responseHeaders.Set("Date", time.Now().UTC().Format(http.TimeFormat))
	}
	// Write the frame
	// TODO: Copy headers
	st.session.out <- synReplyFrame{stream: st, header: st.responseHeaders}
	st.wroteHeader = true
}

// Close sends a closing frame, thus preventing the server from sending more
// data over the stream.  The client may still send data.
func (st *serverStream) Close() (err error) {
	if st.closed {
		return
	}
	st.session.out <- DataFrame{
		StreamID: st.id,
		Flags:    FlagFin,
		Data:     []byte{},
	}
	st.closed = true
	return nil
}

func (st *serverStream) finish() (err error) {
	if !st.wroteHeader {
		st.WriteHeader(http.StatusOK)
	}
	return st.Close()
}
<commit_msg>Fail the session if we could not construct a stream<commit_after>// spdy/server.go

package spdy

import (
	"bytes"
	"crypto/rand"
	"crypto/tls"
	"encoding/binary"
	"errors"
	"io"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

// ListenAndServe creates a new Server that serves on the given address.  If
// the handler is nil, then http.DefaultServeMux is used.
func ListenAndServe(addr string, handler http.Handler) error {
	srv := &Server{addr, handler}
	return srv.ListenAndServe()
}

// ListenAndServeTLS acts like ListenAndServe except it uses TLS.
func ListenAndServeTLS(addr string, certFile, keyFile string, handler http.Handler) (err error) {
	config := &tls.Config{
		Rand:         rand.Reader,
		Time:         time.Now,
		NextProtos:   []string{"spdy/2", "http/1.1"},
		Certificates: make([]tls.Certificate, 1),
	}
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return
	}

	conn, err := net.Listen("tcp", addr)
	if err != nil {
		return
	}
	tlsListener := tls.NewListener(conn, config)
	return (&Server{addr, handler}).Serve(tlsListener)
}

// A Server handles incoming SPDY connections with HTTP handlers.
type Server struct {
	Addr    string
	Handler http.Handler
}

// ListenAndServe services SPDY requests on the given address.
// If the handler is nil, then http.DefaultServeMux is used.
func (srv *Server) ListenAndServe() error {
	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}
	l, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return srv.Serve(l)
}

// ListenAndServe services SPDY requests using the given listener.
// If the handler is nil, then http.DefaultServeMux is used.
func (srv *Server) Serve(l net.Listener) error {
	defer l.Close()
	handler := srv.Handler
	if handler == nil {
		handler = http.DefaultServeMux
	}
	for {
		c, err := l.Accept()
		if err != nil {
			return err
		}
		s, err := newSession(c, handler)
		if err != nil {
			return err
		}
		go s.serve()
	}
	return nil
}

// A session manages a single TCP connection to a client.
type session struct {
	c         net.Conn
	handler   http.Handler
	out       chan Frame
	streams   map[uint32]*serverStream // all access is done synchronously
	last_good uint32

	headerReader *HeaderReader
	headerWriter *HeaderWriter
}

func newSession(c net.Conn, h http.Handler) (s *session, err error) {
	s = &session{
		c:            c,
		handler:      h,
		headerReader: NewHeaderReader(),
		headerWriter: NewHeaderWriter(-1),
		out:          make(chan Frame),
		streams:      make(map[uint32]*serverStream),
		last_good:    0,
	}
	return
}

func (sess *session) serve() {
	defer sess.c.Close()
	go sess.receiveFrames()

	for frame := range sess.out {

		if frame == nil {
			// EOF, signalling end of session
			// initiated by us (on errors, etc.)
			return
		}

		// TODO: Check for errors
		frame.WriteTo(sess.c)
	}
}

func (sess *session) fail() {
	sess.out <- ControlFrame{
		Type: TypeGoaway,
		Data: []byte{
			byte(sess.last_good & 0x7f000000 >> 24),
			byte(sess.last_good & 0x00ff0000 >> 16),
			byte(sess.last_good & 0x0000ff00 >> 8),
			byte(sess.last_good & 0x000000ff >> 0),
		},
	}
	sess.out <- nil
}

func (sess *session) handleControl(frame ControlFrame) {
	switch frame.Type {
	case TypeSynStream:
		if stream, err := newServerStream(sess, frame); err == nil {
			if _, exists := sess.streams[stream.id]; !exists {
				sess.streams[stream.id] = stream
				sess.last_good = stream.id
				go func() {
					sess.handler.ServeHTTP(stream, stream.Request())
					stream.finish()
				}()
			}
		} else {
			sess.fail()
		}
	case TypeRstStream:
		d := bytes.NewBuffer(frame.Data)
		var streamId, statusCode uint32
		readBinary(d, &streamId, &statusCode)
	case TypePing:
		d := bytes.NewBuffer(frame.Data)
		var pingId uint32
		readBinary(d, &pingId)
		sess.out <- ControlFrame{
			Type: TypePing,
			Data: []byte{
				byte(pingId & 0xff000000 >> 24),
				byte(pingId & 0x00ff0000 >> 16),
				byte(pingId & 0x0000ff00 >> 8),
				byte(pingId & 0x000000ff >> 0),
			},
		}
	}
}

func (sess *session) handleData(frame DataFrame) {
	st, found := sess.streams[frame.StreamID]
	if !found {
		// TODO: Error?
		return
	}
	if st.dataPipe != nil {
		st.dataPipe.write(frame.Data)
		if frame.Flags&FlagFin != 0 {
			st.dataPipe.wclose(nil)
		}
	}
}

func (sess *session) receiveFrames() {
	for {
		f, err := ReadFrame(sess.c)
		if err != nil {
			return
		}

		if f == nil {
			// EOF, signalling end of session
			return
		}
		switch frame := f.(type) {
		case ControlFrame:
			sess.handleControl(frame)
		case DataFrame:
			sess.handleData(frame)
		}
	}
}

// A serverStream is a logical data stream inside a session.  A serverStream
// services a single request.
type serverStream struct {
	id      uint32
	session *session
	closed  bool

	requestHeaders  http.Header
	responseHeaders http.Header
	wroteHeader     bool

	dataPipe *asyncPipe
}

func newServerStream(sess *session, frame ControlFrame) (st *serverStream, err error) {
	if frame.Type != TypeSynStream {
		err = errors.New("Server stream must be created from a SynStream frame")
		return
	}
	st = &serverStream{
		session:         sess,
		responseHeaders: make(http.Header),
	}
	if frame.Flags&FlagFin == 0 {
		// Request body will follow
		st.dataPipe = apipe()
	}
	// Read frame data
	data := bytes.NewBuffer(frame.Data)
	err = binary.Read(data, binary.BigEndian, &st.id)
	if err != nil {
		return
	}
	_, err = io.ReadFull(data, make([]byte, 6)) // skip associated stream ID and priority
	if err != nil {
		return
	}
	st.requestHeaders, err = sess.headerReader.Decode(data.Bytes())
	return
}

// Request returns the request data associated with the serverStream.
func (st *serverStream) Request() (req *http.Request) {
	// TODO: Add more info
	req = &http.Request{
		Method:     st.requestHeaders.Get("method"),
		Proto:      st.requestHeaders.Get("version"),
		Header:     st.requestHeaders,
		Body:       st,
		RemoteAddr: st.session.c.RemoteAddr().String(),
	}
	req.URL, _ = url.ParseRequestURI(st.requestHeaders.Get("url"))
	return
}

func (st *serverStream) Read(p []byte) (n int, err error) {
	return st.dataPipe.read(p)
}

// Header returns the current response headers.
func (st *serverStream) Header() http.Header { return st.responseHeaders }

func (st *serverStream) Write(p []byte) (n int, err error) {
	if st.closed {
		err = errors.New("Write on closed serverStream")
		return
	}
	if !st.wroteHeader {
		st.WriteHeader(http.StatusOK)
	}
	for len(p) > 0 {
		frame := DataFrame{
			StreamID: st.id,
		}
		if len(p) < MaxDataLength {
			frame.Data = make([]byte, len(p))
		} else {
			frame.Data = make([]byte, MaxDataLength)
		}
		copy(frame.Data, p)
		p = p[len(frame.Data):]
		st.session.out <- frame
		n += len(frame.Data)
	}
	return
}

// A synReplyFrame defers header compression until the server writes the frame.
// This is necessary to guarantee correctly ordered compression.
type synReplyFrame struct {
	stream *serverStream
	header http.Header
	flags  FrameFlags
}

func (frame synReplyFrame) GetFlags() FrameFlags {
	return frame.flags
}

func (frame synReplyFrame) GetData() []byte {
	buf := new(bytes.Buffer)
	binary.Write(buf, binary.BigEndian, frame.stream.id&0x7fffffff)
	buf.Write([]byte{0, 0})
	frame.stream.session.headerWriter.WriteHeader(buf, frame.stream.responseHeaders)
	return buf.Bytes()
}

func (frame synReplyFrame) WriteTo(w io.Writer) (n int64, err error) {
	cf := ControlFrame{Type: TypeSynReply, Data: frame.GetData()}
	return cf.WriteTo(w)
}

func (st *serverStream) WriteHeader(code int) {
	if st.wroteHeader {
		return
	}
	st.responseHeaders.Set("status", strconv.Itoa(code)+" "+http.StatusText(code))
	st.responseHeaders.Set("version", "HTTP/1.1")
	if st.responseHeaders.Get("Content-Type") == "" {
		st.responseHeaders.Set("Content-Type", "text/html; charset=utf-8")
	}
	if st.responseHeaders.Get("Date") == "" {
		st.responseHeaders.Set("Date", time.Now().UTC().Format(http.TimeFormat))
	}
	// Write the frame
	// TODO: Copy headers
	st.session.out <- synReplyFrame{stream: st, header: st.responseHeaders}
	st.wroteHeader = true
}

// Close sends a closing frame, thus preventing the server from sending more
// data over the stream.  The client may still send data.
func (st *serverStream) Close() (err error) {
	if st.closed {
		return
	}
	st.session.out <- DataFrame{
		StreamID: st.id,
		Flags:    FlagFin,
		Data:     []byte{},
	}
	st.closed = true
	return nil
}

func (st *serverStream) finish() (err error) {
	if !st.wroteHeader {
		st.WriteHeader(http.StatusOK)
	}
	return st.Close()
}
<|endoftext|>


<commit_before>package air

import (
	"net"
	"sync"
	"time"

	"github.com/valyala/fasthttp"
)

type (
	// Server defines the interface for HTTP server.
	Server interface {
		// SetHandler sets the handler for the HTTP server.
		SetHandler(Handler)

		// SetLogger sets the logger for the HTTP server.
		SetLogger(Logger)

		// Start starts the HTTP server.
		Start() error
	}

	fastServer struct {
		*fasthttp.Server
		config  Config
		handler Handler
		logger  Logger
		pool    *pool
	}

	// Config defines fasthttp config.
	Config struct {
		Address      string        // TCP address to listen on.
		Listener     net.Listener  // Custom `net.Listener`. If set, server accepts connections on it.
		TLSCertFile  string        // TLS certificate file path.
		TLSKeyFile   string        // TLS key file path.
		ReadTimeout  time.Duration // Maximum duration before timing out read of the request.
		WriteTimeout time.Duration // Maximum duration before timing out write of the response.
	}

	// Handler defines an interface to server HTTP requests via `ServeHTTP(Request, Response)`
	// function.
	Handler interface {
		ServeHTTP(Request, Response)
	}

	// handlerFunc is an adapter to allow the use of `func(Request, Response)` as
	// an HTTP handler.
	handlerFunc func(Request, Response)

	pool struct {
		request        sync.Pool
		response       sync.Pool
		requestHeader  sync.Pool
		responseHeader sync.Pool
		uri            sync.Pool
	}
)

// NewServer returns `Server` with provided listen address.
func NewServer(addr string) Server {
	c := Config{Address: addr}
	return NewServerWithConfig(c)
}

// NewServerWithTLS returns `Server` with provided TLS config.
func NewServerWithTLS(addr, certFile, keyFile string) Server {
	c := Config{
		Address:     addr,
		TLSCertFile: certFile,
		TLSKeyFile:  keyFile,
	}
	return NewServerWithConfig(c)
}

// NewServerWithConfig returns `Server` with provided config.
func NewServerWithConfig(c Config) Server {
	s := &fastServer{
		Server: new(fasthttp.Server),
		config: c,
		logger: NewLogger("air"),
	}
	s.pool = &pool{
		request: sync.Pool{
			New: func() interface{} {
				return &fastRequest{logger: s.logger}
			},
		},
		response: sync.Pool{
			New: func() interface{} {
				return &fastResponse{logger: s.logger}
			},
		},
		requestHeader: sync.Pool{
			New: func() interface{} {
				return &fastRequestHeader{}
			},
		},
		responseHeader: sync.Pool{
			New: func() interface{} {
				return &fastResponseHeader{}
			},
		},
		uri: sync.Pool{
			New: func() interface{} {
				return &fastURI{}
			},
		},
	}
	s.handler = handlerFunc(func(req Request, res Response) {
		s.logger.Error("handler not set, use `SetHandler()` to set it.")
	})
	s.ReadTimeout = c.ReadTimeout
	s.WriteTimeout = c.WriteTimeout
	s.Handler = s.ServeHTTP
	return s
}

func (s *fastServer) SetHandler(h Handler) {
	s.handler = h
}

func (s *fastServer) SetLogger(l Logger) {
	s.logger = l
}

func (s *fastServer) Start() error {
	if s.config.Listener == nil {
		return s.startDefaultListener()
	}
	return s.startCustomListener()

}

func (s *fastServer) startDefaultListener() error {
	c := s.config
	if c.TLSCertFile != "" && c.TLSKeyFile != "" {
		return s.ListenAndServeTLS(c.Address, c.TLSCertFile, c.TLSKeyFile)
	}
	return s.ListenAndServe(c.Address)
}

func (s *fastServer) startCustomListener() error {
	c := s.config
	if c.TLSCertFile != "" && c.TLSKeyFile != "" {
		return s.ServeTLS(c.Listener, c.TLSCertFile, c.TLSKeyFile)
	}
	return s.Serve(c.Listener)
}

func (s *fastServer) ServeHTTP(c *fasthttp.RequestCtx) {
	// Request
	req := s.pool.request.Get().(*fastRequest)
	reqHdr := s.pool.requestHeader.Get().(*fastRequestHeader)
	reqURI := s.pool.uri.Get().(*fastURI)
	reqHdr.reset(&c.Request.Header)
	reqURI.reset(c.URI())
	req.reset(c, reqHdr, reqURI)

	// Response
	res := s.pool.response.Get().(*fastResponse)
	resHdr := s.pool.responseHeader.Get().(*fastResponseHeader)
	resHdr.reset(&c.Response.Header)
	res.reset(c, resHdr)

	s.handler.ServeHTTP(req, res)

	// Return to pool
	s.pool.request.Put(req)
	s.pool.requestHeader.Put(reqHdr)
	s.pool.uri.Put(reqURI)
	s.pool.response.Put(res)
	s.pool.responseHeader.Put(resHdr)
}

// ServeHTTP serves HTTP request.
func (h *handlerFunc) ServeHTTP(req Request, res Response) {
	h(req, res)
}

// FastWrapHandler wraps `fasthttp.RequestHandler` into `HandlerFunc`.
func FastWrapHandler(h fasthttp.RequestHandler) HandlerFunc {
	return func(c Context) error {
		req := c.Request().(*fastRequest)
		res := c.Response().(*fastResponse)
		ctx := req.RequestCtx
		h(ctx)
		res.status = ctx.Response.StatusCode()
		res.size = int64(ctx.Response.Header.ContentLength())
		return nil
	}
}

// FastWrapGas wraps `func(fasthttp.RequestHandler) fasthttp.RequestHandler`
// into `GasFunc`
func FastWrapGas(m func(fasthttp.RequestHandler) fasthttp.RequestHandler) GasFunc {
	return func(next HandlerFunc) HandlerFunc {
		return func(c Context) (err error) {
			req := c.Request().(*fastRequest)
			res := c.Response().(*fastResponse)
			ctx := req.RequestCtx
			m(func(ctx *fasthttp.RequestCtx) {
				next(c)
			})(ctx)
			res.status = ctx.Response.StatusCode()
			res.size = int64(ctx.Response.Header.ContentLength())
			return
		}
	}
}
<commit_msg>Fix handlerFunc.ServeHTTP bug<commit_after>package air

import (
	"net"
	"sync"
	"time"

	"github.com/valyala/fasthttp"
)

type (
	// Server defines the interface for HTTP server.
	Server interface {
		// SetHandler sets the handler for the HTTP server.
		SetHandler(Handler)

		// SetLogger sets the logger for the HTTP server.
		SetLogger(Logger)

		// Start starts the HTTP server.
		Start() error
	}

	fastServer struct {
		*fasthttp.Server
		config  Config
		handler Handler
		logger  Logger
		pool    *pool
	}

	// Config defines fasthttp config.
	Config struct {
		Address      string        // TCP address to listen on.
		Listener     net.Listener  // Custom `net.Listener`. If set, server accepts connections on it.
		TLSCertFile  string        // TLS certificate file path.
		TLSKeyFile   string        // TLS key file path.
		ReadTimeout  time.Duration // Maximum duration before timing out read of the request.
		WriteTimeout time.Duration // Maximum duration before timing out write of the response.
	}

	// Handler defines an interface to server HTTP requests via `ServeHTTP(Request, Response)`
	// function.
	Handler interface {
		ServeHTTP(Request, Response)
	}

	// handlerFunc is an adapter to allow the use of `func(Request, Response)` as
	// an HTTP handler.
	handlerFunc func(Request, Response)

	pool struct {
		request        sync.Pool
		response       sync.Pool
		requestHeader  sync.Pool
		responseHeader sync.Pool
		uri            sync.Pool
	}
)

// NewServer returns `Server` with provided listen address.
func NewServer(addr string) Server {
	c := Config{Address: addr}
	return NewServerWithConfig(c)
}

// NewServerWithTLS returns `Server` with provided TLS config.
func NewServerWithTLS(addr, certFile, keyFile string) Server {
	c := Config{
		Address:     addr,
		TLSCertFile: certFile,
		TLSKeyFile:  keyFile,
	}
	return NewServerWithConfig(c)
}

// NewServerWithConfig returns `Server` with provided config.
func NewServerWithConfig(c Config) Server {
	s := &fastServer{
		Server: new(fasthttp.Server),
		config: c,
		logger: NewLogger("air"),
	}
	s.pool = &pool{
		request: sync.Pool{
			New: func() interface{} {
				return &fastRequest{logger: s.logger}
			},
		},
		response: sync.Pool{
			New: func() interface{} {
				return &fastResponse{logger: s.logger}
			},
		},
		requestHeader: sync.Pool{
			New: func() interface{} {
				return &fastRequestHeader{}
			},
		},
		responseHeader: sync.Pool{
			New: func() interface{} {
				return &fastResponseHeader{}
			},
		},
		uri: sync.Pool{
			New: func() interface{} {
				return &fastURI{}
			},
		},
	}
	s.handler = handlerFunc(func(req Request, res Response) {
		s.logger.Error("handler not set, use `SetHandler()` to set it.")
	})
	s.ReadTimeout = c.ReadTimeout
	s.WriteTimeout = c.WriteTimeout
	s.Handler = s.ServeHTTP
	return s
}

func (s *fastServer) SetHandler(h Handler) {
	s.handler = h
}

func (s *fastServer) SetLogger(l Logger) {
	s.logger = l
}

func (s *fastServer) Start() error {
	if s.config.Listener == nil {
		return s.startDefaultListener()
	}
	return s.startCustomListener()

}

func (s *fastServer) startDefaultListener() error {
	c := s.config
	if c.TLSCertFile != "" && c.TLSKeyFile != "" {
		return s.ListenAndServeTLS(c.Address, c.TLSCertFile, c.TLSKeyFile)
	}
	return s.ListenAndServe(c.Address)
}

func (s *fastServer) startCustomListener() error {
	c := s.config
	if c.TLSCertFile != "" && c.TLSKeyFile != "" {
		return s.ServeTLS(c.Listener, c.TLSCertFile, c.TLSKeyFile)
	}
	return s.Serve(c.Listener)
}

func (s *fastServer) ServeHTTP(c *fasthttp.RequestCtx) {
	// Request
	req := s.pool.request.Get().(*fastRequest)
	reqHdr := s.pool.requestHeader.Get().(*fastRequestHeader)
	reqURI := s.pool.uri.Get().(*fastURI)
	reqHdr.reset(&c.Request.Header)
	reqURI.reset(c.URI())
	req.reset(c, reqHdr, reqURI)

	// Response
	res := s.pool.response.Get().(*fastResponse)
	resHdr := s.pool.responseHeader.Get().(*fastResponseHeader)
	resHdr.reset(&c.Response.Header)
	res.reset(c, resHdr)

	s.handler.ServeHTTP(req, res)

	// Return to pool
	s.pool.request.Put(req)
	s.pool.requestHeader.Put(reqHdr)
	s.pool.uri.Put(reqURI)
	s.pool.response.Put(res)
	s.pool.responseHeader.Put(resHdr)
}

// ServeHTTP serves HTTP request.
func (h handlerFunc) ServeHTTP(req Request, res Response) {
	h(req, res)
}

// FastWrapHandler wraps `fasthttp.RequestHandler` into `HandlerFunc`.
func FastWrapHandler(h fasthttp.RequestHandler) HandlerFunc {
	return func(c Context) error {
		req := c.Request().(*fastRequest)
		res := c.Response().(*fastResponse)
		ctx := req.RequestCtx
		h(ctx)
		res.status = ctx.Response.StatusCode()
		res.size = int64(ctx.Response.Header.ContentLength())
		return nil
	}
}

// FastWrapGas wraps `func(fasthttp.RequestHandler) fasthttp.RequestHandler`
// into `GasFunc`
func FastWrapGas(m func(fasthttp.RequestHandler) fasthttp.RequestHandler) GasFunc {
	return func(next HandlerFunc) HandlerFunc {
		return func(c Context) (err error) {
			req := c.Request().(*fastRequest)
			res := c.Response().(*fastResponse)
			ctx := req.RequestCtx
			m(func(ctx *fasthttp.RequestCtx) {
				next(c)
			})(ctx)
			res.status = ctx.Response.StatusCode()
			res.size = int64(ctx.Response.Header.ContentLength())
			return
		}
	}
}
<|endoftext|>


<commit_before>package resources

import (
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/eks"
	"github.com/rebuy-de/aws-nuke/pkg/types"
)

type EKSNodegroup struct {
	svc     *eks.EKS
	cluster *string
	name    *string
}

func init() {
	register("EKSNodegroups", ListEKSNodegroups)
}

func ListEKSNodegroups(sess *session.Session) ([]Resource, error) {
	svc := eks.New(sess)
	clusterNames := []*string{}
	resources := []Resource{}

	clusterInputParams := &eks.ListClustersInput{
		MaxResults: aws.Int64(100),
	}

	// fetch all cluster names
	for {
		resp, err := svc.ListClusters(clusterInputParams)
		if err != nil {
			return nil, err
		}

		for _, cluster := range resp.Clusters {
			clusterNames = append(clusterNames, cluster)
		}

		if resp.NextToken == nil {
			break
		}

		clusterInputParams.NextToken = resp.NextToken
	}

	nodegroupsInputParams := &eks.ListNodegroupsInput{
		MaxResults: aws.Int64(100),
	}

	// fetch the associated node groups
	for _, clusterName := range clusterNames {
		nodegroupsInputParams.ClusterName = clusterName

		for {
			resp, err := svc.ListNodegroups(nodegroupsInputParams)
			if err != nil {
				return nil, err
			}

			for _, name := range resp.Nodegroups {
				resources = append(resources, &EKSNodegroup{
					svc:     svc,
					name:    name,
					cluster: clusterName,
				})
			}

			if resp.NextToken == nil {
				nodegroupsInputParams.NextToken = nil
				break
			}

			nodegroupsInputParams.NextToken = resp.NextToken
		}

	}

	return resources, nil
}

func (ng *EKSNodegroup) Remove() error {
	_, err := ng.svc.DeleteNodegroup(&eks.DeleteNodegroupInput{
		ClusterName:   ng.cluster,
		NodegroupName: ng.name,
	})
	return err
}

func (ng *EKSNodegroup) Properties() types.Properties {
	return types.NewProperties().
		Set("Cluster", *ng.cluster).
		Set("Profile", *ng.name)
}

func (ng *EKSNodegroup) String() string {
	return fmt.Sprintf("%s:%s", *ng.cluster, *ng.name)
}
<commit_msg>Add `CreatedAt` property to EKS nodegroups (#680)<commit_after>package resources

import (
	"fmt"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/eks"
	"github.com/rebuy-de/aws-nuke/pkg/types"
)

type EKSNodegroup struct {
	svc       *eks.EKS
	nodegroup *eks.Nodegroup
}

func init() {
	register("EKSNodegroups", ListEKSNodegroups)
}

func ListEKSNodegroups(sess *session.Session) ([]Resource, error) {
	svc := eks.New(sess)
	clusterNames := []*string{}
	resources := []Resource{}

	clusterInputParams := &eks.ListClustersInput{
		MaxResults: aws.Int64(100),
	}

	// fetch all cluster names
	for {
		resp, err := svc.ListClusters(clusterInputParams)
		if err != nil {
			return nil, err
		}

		for _, cluster := range resp.Clusters {
			clusterNames = append(clusterNames, cluster)
		}

		if resp.NextToken == nil {
			break
		}

		clusterInputParams.NextToken = resp.NextToken
	}

	nodegroupsInputParams := &eks.ListNodegroupsInput{
		MaxResults: aws.Int64(100),
	}
	describeNodegroupInputParams := &eks.DescribeNodegroupInput{}

	// fetch the associated node groups
	for _, clusterName := range clusterNames {
		nodegroupsInputParams.ClusterName = clusterName
		describeNodegroupInputParams.ClusterName = clusterName

		for {
			resp, err := svc.ListNodegroups(nodegroupsInputParams)
			if err != nil {
				return nil, err
			}

			for _, nodegroupName := range resp.Nodegroups {
				describeNodegroupInputParams.NodegroupName = nodegroupName
				nodegroupDescriptionResponse, err := svc.DescribeNodegroup(describeNodegroupInputParams)
				if err != nil {
					return nil, err
				}
				resources = append(resources, &EKSNodegroup{
					svc:       svc,
					nodegroup: nodegroupDescriptionResponse.Nodegroup,
				})
			}

			if resp.NextToken == nil {
				nodegroupsInputParams.NextToken = nil
				break
			}

			nodegroupsInputParams.NextToken = resp.NextToken
		}
	}

	return resources, nil
}

func (ng *EKSNodegroup) Remove() error {
	_, err := ng.svc.DeleteNodegroup(&eks.DeleteNodegroupInput{
		ClusterName:   ng.nodegroup.ClusterName,
		NodegroupName: ng.nodegroup.NodegroupName,
	})
	return err
}

func (ng *EKSNodegroup) Properties() types.Properties {
	properties := types.NewProperties()
	properties.Set("Cluster", ng.nodegroup.ClusterName)
	properties.Set("Profile", ng.nodegroup.NodegroupName)
	if ng.nodegroup.CreatedAt != nil {
		properties.Set("CreatedAt", ng.nodegroup.CreatedAt.Format(time.RFC3339))
	}
	return properties
}

func (ng *EKSNodegroup) String() string {
	return fmt.Sprintf("%s:%s", *ng.nodegroup.ClusterName, *ng.nodegroup.NodegroupName)
}
<|endoftext|>


<commit_before>package filer

import (
	"bytes"
	"math"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/chrislusf/seaweedfs/weed/util"
)

// onMetadataChangeEvent is triggered after filer processed change events from local or remote filers
func (f *Filer) onMetadataChangeEvent(event *filer_pb.SubscribeMetadataResponse) {
	if DirectoryEtcSeaweedFS != event.Directory {
		if DirectoryEtcSeaweedFS != event.EventNotification.NewParentPath {
			return
		}
	}

	entry := event.EventNotification.NewEntry
	if entry == nil {
		return
	}

	glog.V(0).Infof("procesing %v", event)
	if entry.Name == FilerConfName {
		f.reloadFilerConfiguration(entry)
	}

}

func (f *Filer) readEntry(chunks []*filer_pb.FileChunk) ([]byte, error) {
	var buf bytes.Buffer
	err := StreamContent(f.MasterClient, &buf, chunks, 0, math.MaxInt64)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (f *Filer) reloadFilerConfiguration(entry *filer_pb.Entry) {
	fc := NewFilerConf()
	err := fc.loadFromChunks(f, entry.Content, entry.Chunks)
	if err != nil {
		glog.Errorf("read filer conf chunks: %v", err)
		return
	}
	f.FilerConf = fc
}

func (f *Filer) LoadFilerConf() {
	fc := NewFilerConf()
	err := util.Retry("loadFilerConf", func() error {
		return fc.loadFromFiler(f)
	})
	if err != nil {
		glog.Errorf("read filer conf: %v", err)
		return
	}
	f.FilerConf = fc
}
<commit_msg>refactor<commit_after>package filer

import (
	"bytes"
	"math"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/chrislusf/seaweedfs/weed/util"
)

// onMetadataChangeEvent is triggered after filer processed change events from local or remote filers
func (f *Filer) onMetadataChangeEvent(event *filer_pb.SubscribeMetadataResponse) {
	f.maybeReloadFilerConfiguration(event)
}

func (f *Filer) maybeReloadFilerConfiguration(event *filer_pb.SubscribeMetadataResponse) {
	if DirectoryEtcSeaweedFS != event.Directory {
		if DirectoryEtcSeaweedFS != event.EventNotification.NewParentPath {
			return
		}
	}

	entry := event.EventNotification.NewEntry
	if entry == nil {
		return
	}

	glog.V(0).Infof("procesing %v", event)
	if entry.Name == FilerConfName {
		f.reloadFilerConfiguration(entry)
	}
}

func (f *Filer) readEntry(chunks []*filer_pb.FileChunk) ([]byte, error) {
	var buf bytes.Buffer
	err := StreamContent(f.MasterClient, &buf, chunks, 0, math.MaxInt64)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (f *Filer) reloadFilerConfiguration(entry *filer_pb.Entry) {
	fc := NewFilerConf()
	err := fc.loadFromChunks(f, entry.Content, entry.Chunks)
	if err != nil {
		glog.Errorf("read filer conf chunks: %v", err)
		return
	}
	f.FilerConf = fc
}

func (f *Filer) LoadFilerConf() {
	fc := NewFilerConf()
	err := util.Retry("loadFilerConf", func() error {
		return fc.loadFromFiler(f)
	})
	if err != nil {
		glog.Errorf("read filer conf: %v", err)
		return
	}
	f.FilerConf = fc
}
<|endoftext|>


<commit_before>package splash

import (
	"bufio"
	"fmt"
	"github.com/Symantec/scotty/datastructs"
	"html/template"
	"io"
	"net/http"
	"regexp"
	"strings"
)

const (
	htmlTemplateStr = ` \
	Total apps: {{.TotalApps}}

	Total failed apps: {{.TotalFailedApps}}

	Applications

	Metrics

	  `
)

var (
	leadingWhitespace = regexp.MustCompile(`\n\s*\\ `)
	htmlTemplate      = template.Must(
		template.New("splash").Parse(
			strings.Replace(
				leadingWhitespace.ReplaceAllString(
					strings.Replace(
						htmlTemplateStr,
						"\n\t",
						"\n",
						-1),
					"\n"),
				" \\\n",
				"",
				-1)))
)

type view struct {
	TotalApps       int
	TotalFailedApps int
}

func newView(
	apps []*datastructs.ApplicationStatus) *view {
	result := &view{}
	for _, app := range apps {
		if app.Down {
			result.TotalFailedApps++
		}
		result.TotalApps++
	}
	return result
}

type HtmlWriter interface {
	WriteHtml(writer io.Writer)
}

type Handler struct {
	HPS *datastructs.HostsPortsAndStore
	AS  *datastructs.ApplicationStatuses
	Log HtmlWriter
}

func (h *Handler) ServeHTTP(
	w http.ResponseWriter, r *http.Request) {
	writer := bufio.NewWriter(w)
	defer writer.Flush()
	w.Header().Set("Content-Type", "text/html")
	_, hostsAndPorts := h.HPS.Get()
	result := h.AS.GetAll(hostsAndPorts)
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "")
	v := newView(result)
	if err := htmlTemplate.Execute(writer, v); err != nil {
		fmt.Fprintln(writer, "Error in template: %v\n", err)
		fmt.Fprintln(writer, "")
		fmt.Fprintln(writer, "")
	}
	h.Log.WriteHtml(writer)
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "")
}
<commit_msg>Add header status to splash page and a title.<commit_after>package splash

import (
	"bufio"
	"fmt"
	"github.com/Symantec/Dominator/lib/html"
	"github.com/Symantec/scotty/datastructs"
	"html/template"
	"io"
	"net/http"
	"regexp"
	"strings"
)

const (
	htmlTemplateStr = ` \
	Applications

	Total apps: {{.TotalApps}}

	Total failed apps: {{.TotalFailedApps}}

	  `
)

var (
	leadingWhitespace = regexp.MustCompile(`\n\s*\\ `)
	htmlTemplate      = template.Must(
		template.New("splash").Parse(
			strings.Replace(
				leadingWhitespace.ReplaceAllString(
					strings.Replace(
						htmlTemplateStr,
						"\n\t",
						"\n",
						-1),
					"\n"),
				" \\\n",
				"",
				-1)))
)

type view struct {
	TotalApps       int
	TotalFailedApps int
}

func newView(
	apps []*datastructs.ApplicationStatus) *view {
	result := &view{}
	for _, app := range apps {
		if app.Down {
			result.TotalFailedApps++
		}
		result.TotalApps++
	}
	return result
}

type HtmlWriter interface {
	WriteHtml(writer io.Writer)
}

type Handler struct {
	HPS *datastructs.HostsPortsAndStore
	AS  *datastructs.ApplicationStatuses
	Log HtmlWriter
}

func (h *Handler) ServeHTTP(
	w http.ResponseWriter, r *http.Request) {
	writer := bufio.NewWriter(w)
	defer writer.Flush()
	w.Header().Set("Content-Type", "text/html")
	_, hostsAndPorts := h.HPS.Get()
	result := h.AS.GetAll(hostsAndPorts)
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "<title>Scotty status page</title>")
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "
Scotty status page
")
	fmt.Fprintln(writer, "")
	html.WriteHeader(writer)
	fmt.Fprintln(writer, "
")
	v := newView(result)
	if err := htmlTemplate.Execute(writer, v); err != nil {
		fmt.Fprintln(writer, "Error in template: %v\n", err)
		fmt.Fprintln(writer, "")
		fmt.Fprintln(writer, "")
	}
	h.Log.WriteHtml(writer)
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "")
}
<|endoftext|>


<commit_before>// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package client

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"github.com/gogf/gf/internal/intlog"
	"github.com/gogf/gf/internal/json"
	"github.com/gogf/gf/internal/utils"
	"github.com/gogf/gf/net/ghttp/internal/httputil"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/gogf/gf/encoding/gparser"
	"github.com/gogf/gf/text/gregex"
	"github.com/gogf/gf/text/gstr"
	"github.com/gogf/gf/util/gconv"

	"github.com/gogf/gf/os/gfile"
)

// Get send GET request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Get(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("GET", url, data...)
}

// Put send PUT request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Put(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("PUT", url, data...)
}

// Post sends request using HTTP method POST and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Post(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("POST", url, data...)
}

// Delete send DELETE request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Delete(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("DELETE", url, data...)
}

// Head send HEAD request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Head(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("HEAD", url, data...)
}

// Patch send PATCH request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Patch(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("PATCH", url, data...)
}

// Connect send CONNECT request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Connect(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("CONNECT", url, data...)
}

// Options send OPTIONS request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Options(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("OPTIONS", url, data...)
}

// Trace send TRACE request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Trace(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("TRACE", url, data...)
}

// DoRequest sends request with given HTTP method and data and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
//
// Note that it uses "multipart/form-data" as its Content-Type if it contains file uploading,
// else it uses "application/x-www-form-urlencoded". It also automatically detects the post
// content for JSON format, and for that it automatically sets the Content-Type as
// "application/json".
func (c *Client) DoRequest(method, url string, data ...interface{}) (resp *Response, err error) {
	req, err := c.prepareRequest(method, url, data...)
	if err != nil {
		return nil, err
	}

	// Client middleware.
	if len(c.middlewareHandler) > 0 {
		mdlHandlers := make([]HandlerFunc, 0, len(c.middlewareHandler)+1)
		mdlHandlers = append(mdlHandlers, c.middlewareHandler...)
		mdlHandlers = append(mdlHandlers, func(cli *Client, r *http.Request) (*Response, error) {
			return cli.callRequest(r)
		})
		ctx := context.WithValue(req.Context(), clientMiddlewareKey, &clientMiddleware{
			client:       c,
			handlers:     mdlHandlers,
			handlerIndex: -1,
		})
		req = req.WithContext(ctx)
		resp, err = c.Next(req)
	} else {
		resp, err = c.callRequest(req)
	}

	// Auto saving cookie content.
	if c.browserMode && resp != nil && resp.Response != nil {
		now := time.Now()
		for _, v := range resp.Response.Cookies() {
			if !v.Expires.IsZero() && v.Expires.UnixNano() < now.UnixNano() {
				delete(c.cookies, v.Name)
			} else {
				c.cookies[v.Name] = v.Value
			}
		}
	}
	return resp, err
}

// prepareRequest verifies request parameters, builds and returns http request.
func (c *Client) prepareRequest(method, url string, data ...interface{}) (req *http.Request, err error) {
	method = strings.ToUpper(method)
	if len(c.prefix) > 0 {
		url = c.prefix + gstr.Trim(url)
	}
	param := ""
	if len(data) > 0 {
		switch c.header["Content-Type"] {
		case "application/json":
			switch data[0].(type) {
			case string, []byte:
				param = gconv.String(data[0])
			default:
				if b, err := json.Marshal(data[0]); err != nil {
					return nil, err
				} else {
					param = gconv.UnsafeBytesToStr(b)
				}
			}
		case "application/xml":
			switch data[0].(type) {
			case string, []byte:
				param = gconv.String(data[0])
			default:
				if b, err := gparser.VarToXml(data[0]); err != nil {
					return nil, err
				} else {
					param = gconv.UnsafeBytesToStr(b)
				}
			}
		default:
			param = httputil.BuildParams(data[0])
		}
	}
	if method == "GET" {
		// It appends the parameters to the url if http method is GET.
		if param != "" {
			if gstr.Contains(url, "?") {
				url = url + "&" + param
			} else {
				url = url + "?" + param
			}
		}
		if req, err = http.NewRequest(method, url, bytes.NewBuffer(nil)); err != nil {
			return nil, err
		}
	} else {
		if strings.Contains(param, "@file:") {
			// File uploading request.
			buffer := new(bytes.Buffer)
			writer := multipart.NewWriter(buffer)
			for _, item := range strings.Split(param, "&") {
				array := strings.Split(item, "=")
				if len(array[1]) > 6 && strings.Compare(array[1][0:6], "@file:") == 0 {
					path := array[1][6:]
					if !gfile.Exists(path) {
						return nil, errors.New(fmt.Sprintf(`"%s" does not exist`, path))
					}
					if file, err := writer.CreateFormFile(array[0], gfile.Basename(path)); err == nil {
						if f, err := os.Open(path); err == nil {
							if _, err = io.Copy(file, f); err != nil {
								if err := f.Close(); err != nil {
									intlog.Errorf(`%+v`, err)
								}
								return nil, err
							}
							if err := f.Close(); err != nil {
								intlog.Errorf(`%+v`, err)
							}
						} else {
							return nil, err
						}
					} else {
						return nil, err
					}
				} else {
					if err = writer.WriteField(array[0], array[1]); err != nil {
						return nil, err
					}
				}
			}
			// Close finishes the multipart message and writes the trailing
			// boundary end line to the output.
			if err = writer.Close(); err != nil {
				return nil, err
			}

			if req, err = http.NewRequest(method, url, buffer); err != nil {
				return nil, err
			} else {
				req.Header.Set("Content-Type", writer.FormDataContentType())
			}
		} else {
			// Normal request.
			paramBytes := []byte(param)
			if req, err = http.NewRequest(method, url, bytes.NewReader(paramBytes)); err != nil {
				return nil, err
			} else {
				if v, ok := c.header["Content-Type"]; ok {
					// Custom Content-Type.
					req.Header.Set("Content-Type", v)
				} else if len(paramBytes) > 0 {
					if (paramBytes[0] == '[' || paramBytes[0] == '{') && json.Valid(paramBytes) {
						// Auto detecting and setting the post content format: JSON.
						req.Header.Set("Content-Type", "application/json")
					} else if gregex.IsMatchString(`^[\w\[\]]+=.+`, param) {
						// If the parameters passed like "name=value", it then uses form type.
						req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
					}
				}
			}
		}
	}

	// Context.
	if c.ctx != nil {
		req = req.WithContext(c.ctx)
	} else {
		req = req.WithContext(context.Background())
	}
	// Custom header.
	if len(c.header) > 0 {
		for k, v := range c.header {
			req.Header.Set(k, v)
		}
	}
	// It's necessary set the req.Host if you want to custom the host value of the request.
	// It uses the "Host" value from header if it's not empty.
	if host := req.Header.Get("Host"); host != "" {
		req.Host = host
	}
	// Custom Cookie.
	if len(c.cookies) > 0 {
		headerCookie := ""
		for k, v := range c.cookies {
			if len(headerCookie) > 0 {
				headerCookie += ";"
			}
			headerCookie += k + "=" + v
		}
		if len(headerCookie) > 0 {
			req.Header.Set("Cookie", headerCookie)
		}
	}
	// HTTP basic authentication.
	if len(c.authUser) > 0 {
		req.SetBasicAuth(c.authUser, c.authPass)
	}
	return req, nil
}

// callRequest sends request with give http.Request, and returns the responses object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) callRequest(req *http.Request) (resp *Response, err error) {
	resp = &Response{
		request: req,
	}
	// Dump feature.
	// The request body can be reused for dumping
	// raw HTTP request-response procedure.
	if c.dump {
		reqBodyContent, _ := ioutil.ReadAll(req.Body)
		resp.requestBody = reqBodyContent
		req.Body = utils.NewReadCloser(reqBodyContent, false)
	}
	for {
		if resp.Response, err = c.Do(req); err != nil {
			// The response might not be nil when err != nil.
			if resp.Response != nil {
				if err := resp.Response.Body.Close(); err != nil {
					intlog.Errorf(`%+v`, err)
				}
			}
			if c.retryCount > 0 {
				c.retryCount--
				time.Sleep(c.retryInterval)
			} else {
				//return resp, err
				break
			}
		} else {
			break
		}
	}
	return resp, err
}
<commit_msg>improve ghttp.Client for #1179<commit_after>// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package client

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"github.com/gogf/gf/internal/intlog"
	"github.com/gogf/gf/internal/json"
	"github.com/gogf/gf/internal/utils"
	"github.com/gogf/gf/net/ghttp/internal/httputil"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/gogf/gf/encoding/gparser"
	"github.com/gogf/gf/text/gregex"
	"github.com/gogf/gf/text/gstr"
	"github.com/gogf/gf/util/gconv"

	"github.com/gogf/gf/os/gfile"
)

// Get send GET request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Get(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("GET", url, data...)
}

// Put send PUT request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Put(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("PUT", url, data...)
}

// Post sends request using HTTP method POST and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Post(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("POST", url, data...)
}

// Delete send DELETE request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Delete(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("DELETE", url, data...)
}

// Head send HEAD request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Head(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("HEAD", url, data...)
}

// Patch send PATCH request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Patch(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("PATCH", url, data...)
}

// Connect send CONNECT request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Connect(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("CONNECT", url, data...)
}

// Options send OPTIONS request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Options(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("OPTIONS", url, data...)
}

// Trace send TRACE request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Trace(url string, data ...interface{}) (*Response, error) {
	return c.DoRequest("TRACE", url, data...)
}

// DoRequest sends request with given HTTP method and data and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
//
// Note that it uses "multipart/form-data" as its Content-Type if it contains file uploading,
// else it uses "application/x-www-form-urlencoded". It also automatically detects the post
// content for JSON format, and for that it automatically sets the Content-Type as
// "application/json".
func (c *Client) DoRequest(method, url string, data ...interface{}) (resp *Response, err error) {
	req, err := c.prepareRequest(method, url, data...)
	if err != nil {
		return nil, err
	}

	// Client middleware.
	if len(c.middlewareHandler) > 0 {
		mdlHandlers := make([]HandlerFunc, 0, len(c.middlewareHandler)+1)
		mdlHandlers = append(mdlHandlers, c.middlewareHandler...)
		mdlHandlers = append(mdlHandlers, func(cli *Client, r *http.Request) (*Response, error) {
			return cli.callRequest(r)
		})
		ctx := context.WithValue(req.Context(), clientMiddlewareKey, &clientMiddleware{
			client:       c,
			handlers:     mdlHandlers,
			handlerIndex: -1,
		})
		req = req.WithContext(ctx)
		resp, err = c.Next(req)
	} else {
		resp, err = c.callRequest(req)
	}

	// Auto saving cookie content.
	if c.browserMode && resp != nil && resp.Response != nil {
		now := time.Now()
		for _, v := range resp.Response.Cookies() {
			if !v.Expires.IsZero() && v.Expires.UnixNano() < now.UnixNano() {
				delete(c.cookies, v.Name)
			} else {
				c.cookies[v.Name] = v.Value
			}
		}
	}
	return resp, err
}

// prepareRequest verifies request parameters, builds and returns http request.
func (c *Client) prepareRequest(method, url string, data ...interface{}) (req *http.Request, err error) {
	method = strings.ToUpper(method)
	if len(c.prefix) > 0 {
		url = c.prefix + gstr.Trim(url)
	}
	var params string
	if len(data) > 0 {
		switch c.header["Content-Type"] {
		case "application/json":
			switch data[0].(type) {
			case string, []byte:
				params = gconv.String(data[0])
			default:
				if b, err := json.Marshal(data[0]); err != nil {
					return nil, err
				} else {
					params = string(b)
				}
			}
		case "application/xml":
			switch data[0].(type) {
			case string, []byte:
				params = gconv.String(data[0])
			default:
				if b, err := gparser.VarToXml(data[0]); err != nil {
					return nil, err
				} else {
					params = string(b)
				}
			}
		default:
			params = httputil.BuildParams(data[0])
		}
	}
	if method == "GET" {
		var bodyBuffer *bytes.Buffer
		if params != "" {
			switch c.header["Content-Type"] {
			case
				"application/json",
				"application/xml":
				bodyBuffer = bytes.NewBuffer([]byte(params))
			default:
				// It appends the parameters to the url
				// if http method is GET and Content-Type is not specified.
				if gstr.Contains(url, "?") {
					url = url + "&" + params
				} else {
					url = url + "?" + params
				}
				bodyBuffer = bytes.NewBuffer(nil)
			}
		} else {
			bodyBuffer = bytes.NewBuffer(nil)
		}
		if req, err = http.NewRequest(method, url, bodyBuffer); err != nil {
			return nil, err
		}
	} else {
		if strings.Contains(params, "@file:") {
			// File uploading request.
			var (
				buffer = bytes.NewBuffer(nil)
				writer = multipart.NewWriter(buffer)
			)
			for _, item := range strings.Split(params, "&") {
				array := strings.Split(item, "=")
				if len(array[1]) > 6 && strings.Compare(array[1][0:6], "@file:") == 0 {
					path := array[1][6:]
					if !gfile.Exists(path) {
						return nil, errors.New(fmt.Sprintf(`"%s" does not exist`, path))
					}
					if file, err := writer.CreateFormFile(array[0], gfile.Basename(path)); err == nil {
						if f, err := os.Open(path); err == nil {
							if _, err = io.Copy(file, f); err != nil {
								if err := f.Close(); err != nil {
									intlog.Errorf(`%+v`, err)
								}
								return nil, err
							}
							if err := f.Close(); err != nil {
								intlog.Errorf(`%+v`, err)
							}
						} else {
							return nil, err
						}
					} else {
						return nil, err
					}
				} else {
					if err = writer.WriteField(array[0], array[1]); err != nil {
						return nil, err
					}
				}
			}
			// Close finishes the multipart message and writes the trailing
			// boundary end line to the output.
			if err = writer.Close(); err != nil {
				return nil, err
			}

			if req, err = http.NewRequest(method, url, buffer); err != nil {
				return nil, err
			} else {
				req.Header.Set("Content-Type", writer.FormDataContentType())
			}
		} else {
			// Normal request.
			paramBytes := []byte(params)
			if req, err = http.NewRequest(method, url, bytes.NewReader(paramBytes)); err != nil {
				return nil, err
			} else {
				if v, ok := c.header["Content-Type"]; ok {
					// Custom Content-Type.
					req.Header.Set("Content-Type", v)
				} else if len(paramBytes) > 0 {
					if (paramBytes[0] == '[' || paramBytes[0] == '{') && json.Valid(paramBytes) {
						// Auto detecting and setting the post content format: JSON.
						req.Header.Set("Content-Type", "application/json")
					} else if gregex.IsMatchString(`^[\w\[\]]+=.+`, params) {
						// If the parameters passed like "name=value", it then uses form type.
						req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
					}
				}
			}
		}
	}

	// Context.
	if c.ctx != nil {
		req = req.WithContext(c.ctx)
	} else {
		req = req.WithContext(context.Background())
	}
	// Custom header.
	if len(c.header) > 0 {
		for k, v := range c.header {
			req.Header.Set(k, v)
		}
	}
	// It's necessary set the req.Host if you want to custom the host value of the request.
	// It uses the "Host" value from header if it's not empty.
	if host := req.Header.Get("Host"); host != "" {
		req.Host = host
	}
	// Custom Cookie.
	if len(c.cookies) > 0 {
		headerCookie := ""
		for k, v := range c.cookies {
			if len(headerCookie) > 0 {
				headerCookie += ";"
			}
			headerCookie += k + "=" + v
		}
		if len(headerCookie) > 0 {
			req.Header.Set("Cookie", headerCookie)
		}
	}
	// HTTP basic authentication.
	if len(c.authUser) > 0 {
		req.SetBasicAuth(c.authUser, c.authPass)
	}
	return req, nil
}

// callRequest sends request with give http.Request, and returns the responses object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) callRequest(req *http.Request) (resp *Response, err error) {
	resp = &Response{
		request: req,
	}
	// Dump feature.
	// The request body can be reused for dumping
	// raw HTTP request-response procedure.
	if c.dump {
		reqBodyContent, _ := ioutil.ReadAll(req.Body)
		resp.requestBody = reqBodyContent
		req.Body = utils.NewReadCloser(reqBodyContent, false)
	}
	for {
		if resp.Response, err = c.Do(req); err != nil {
			// The response might not be nil when err != nil.
			if resp.Response != nil {
				if err := resp.Response.Body.Close(); err != nil {
					intlog.Errorf(`%+v`, err)
				}
			}
			if c.retryCount > 0 {
				c.retryCount--
				time.Sleep(c.retryInterval)
			} else {
				//return resp, err
				break
			}
		} else {
			break
		}
	}
	return resp, err
}
<|endoftext|>


<commit_before>package main

import "fmt"

// A resource is something that can be deleted. Rating provides an indication
// of how "valuable" it is. A higher value means it should be preserved in
// favour of a resource with a lower rating.
type Resource interface {
	Rating() float64
	Expunge() error
}

// Resources is a type that can be sorted in order to establish in which order
// resources should be expunged.
type Resources []Resource

func (r Resources) Empty() bool {
	return len(r) == 0
}

func (r *Resources) ExpungeNext() error {
	err := (*r)[0].Expunge()
	if err != nil {
		return err
	}
	*r = (*r)[1:]
	return nil
}

// Implement sort.Interface to sort by deletion order.
func (rs Resources) Len() int {
	return len(rs)
}

func (rs Resources) Less(i, j int) bool {
	return rs[i].Rating() < rs[j].Rating()
}

func (rs Resources) Swap(i, j int) {
	rs[i], rs[j] = rs[j], rs[i]
}

// Note ideally this would run in an independent thread, but since we have one
// job at a time, we can sequence it between task runs. Also it should be
// independent of mounts feature, but let's go with it here as currently that
// is the only feature that uses it.
func runGarbageCollection(r Resources) error {
	currentFreeSpace, err := freeDiskSpaceBytes(TaskUser.HomeDir)
	if err != nil {
		return fmt.Errorf("Could not calculate free disk space in dir %v due to error %#v", TaskUser.HomeDir, err)
	}
	requiredFreeSpace := uint64(config.RequiredDiskSpaceMegabytes * 1024 * 1024)
	for currentFreeSpace < requiredFreeSpace {
		// need to free up space
		if r.Empty() {
			break
		}
		err = r.ExpungeNext()
		if err != nil {
			return err
		}
		currentFreeSpace, err = freeDiskSpaceBytes(TaskUser.HomeDir)
		if err != nil {
			return err
		}
	}
	if currentFreeSpace < requiredFreeSpace {
		return fmt.Errorf("Not able to free up enough disk space - require %v bytes, but only have %v bytes - and nothing left to delete.", requiredFreeSpace, currentFreeSpace)
	}
	return nil
}
<commit_msg>Fix for incorrect calculations on 32 bit systems<commit_after>package main

import "fmt"

// A resource is something that can be deleted. Rating provides an indication
// of how "valuable" it is. A higher value means it should be preserved in
// favour of a resource with a lower rating.
type Resource interface {
	Rating() float64
	Expunge() error
}

// Resources is a type that can be sorted in order to establish in which order
// resources should be expunged.
type Resources []Resource

func (r Resources) Empty() bool {
	return len(r) == 0
}

func (r *Resources) ExpungeNext() error {
	err := (*r)[0].Expunge()
	if err != nil {
		return err
	}
	*r = (*r)[1:]
	return nil
}

// Implement sort.Interface to sort by deletion order.
func (rs Resources) Len() int {
	return len(rs)
}

func (rs Resources) Less(i, j int) bool {
	return rs[i].Rating() < rs[j].Rating()
}

func (rs Resources) Swap(i, j int) {
	rs[i], rs[j] = rs[j], rs[i]
}

// Note ideally this would run in an independent thread, but since we have one
// job at a time, we can sequence it between task runs. Also it should be
// independent of mounts feature, but let's go with it here as currently that
// is the only feature that uses it.
func runGarbageCollection(r Resources) error {
	currentFreeSpace, err := freeDiskSpaceBytes(TaskUser.HomeDir)
	if err != nil {
		return fmt.Errorf("Could not calculate free disk space in dir %v due to error %#v", TaskUser.HomeDir, err)
	}
	requiredFreeSpace := uint64(config.RequiredDiskSpaceMegabytes) * 1024 * 1024
	for currentFreeSpace < requiredFreeSpace {
		// need to free up space
		if r.Empty() {
			break
		}
		err = r.ExpungeNext()
		if err != nil {
			return err
		}
		currentFreeSpace, err = freeDiskSpaceBytes(TaskUser.HomeDir)
		if err != nil {
			return err
		}
	}
	if currentFreeSpace < requiredFreeSpace {
		return fmt.Errorf("Not able to free up enough disk space - require %v bytes, but only have %v bytes - and nothing left to delete.", requiredFreeSpace, currentFreeSpace)
	}
	return nil
}
<|endoftext|>


<commit_before>package generator

const writeDoubleMethod = `
func writeDouble(r float64, w io.Writer) error {
	bits := uint64(math.Float64bits(r))
	const byteCount = 8
	return encodeFloat(w, byteCount, bits)
}
`

type doubleField struct {
	name         string
	defaultValue float64
	hasDefault   bool
}

func (s *doubleField) Name() string {
	return toPublicName(s.name)
}

func (s *doubleField) FieldType() string {
	return "Double"
}

func (s *doubleField) GoType() string {
	return "float64"
}

func (s *doubleField) SerializerMethod() string {
	return "writeDouble"
}

func (s *doubleField) AddStruct(*Package) {}

func (s *doubleField) AddSerializer(p *Package) {
	p.addStruct(UTIL_FILE, "ByteWriter", byteWriterInterface)
	p.addFunction(UTIL_FILE, "", "writeDouble", writeDoubleMethod)
	p.addFunction(UTIL_FILE, "", "encodeFloat", encodeFloatMethod)
	p.addImport(UTIL_FILE, "io")
}
<commit_msg>Add "math" import for double primitives<commit_after>package generator

const writeDoubleMethod = `
func writeDouble(r float64, w io.Writer) error {
	bits := uint64(math.Float64bits(r))
	const byteCount = 8
	return encodeFloat(w, byteCount, bits)
}
`

type doubleField struct {
	name         string
	defaultValue float64
	hasDefault   bool
}

func (s *doubleField) Name() string {
	return toPublicName(s.name)
}

func (s *doubleField) FieldType() string {
	return "Double"
}

func (s *doubleField) GoType() string {
	return "float64"
}

func (s *doubleField) SerializerMethod() string {
	return "writeDouble"
}

func (s *doubleField) AddStruct(*Package) {}

func (s *doubleField) AddSerializer(p *Package) {
	p.addStruct(UTIL_FILE, "ByteWriter", byteWriterInterface)
	p.addFunction(UTIL_FILE, "", "writeDouble", writeDoubleMethod)
	p.addFunction(UTIL_FILE, "", "encodeFloat", encodeFloatMethod)
	p.addImport(UTIL_FILE, "io")
	p.addImport(UTIL_FILE, "math")
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// More information about Google Geolocation API is available on
// https://developers.google.com/maps/documentation/geolocation

package maps

import (
	"context"
	"reflect"
	"testing"
)

func TestGeolocation(t *testing.T) {

	// Elevation of Denver, the mile high city
	response := `{
		"location" : {
			"lat" : 39.73915360,
			"lng" : -104.98470340
		},
		"accuracy" : 4.771975994110107
	}`

	server := mockServer(200, response)
	defer server.Close()
	c, _ := NewClient(WithAPIKey(apiKey))
	c.baseURL = server.URL
	r := &GeolocationRequest{}

	resp, err := c.Geolocate(context.Background(), r)
	if err != nil {
		t.Errorf("r.Get returned non nil error, was %+v", err)
	}

	correctResponse := GeolocationResult{
		Location: LatLng{
			Lat: 39.73915360,
			Lng: -104.98470340,
		},
		Accuracy: 4.771975994110107,
	}

	if !reflect.DeepEqual(*resp, correctResponse) {
		t.Errorf("expected %+v, was %+v", correctResponse, resp)
	}
}

func TestGeolocationError(t *testing.T) {

	// Elevation of Denver, the mile high city
	response := `{
		"error": {
			"errors": [
				{
					"domain": "global",
					"reason": "invalid",
					"message": "Invalid value for UnsignedInteger: ",
					"locationType": "other",
					"location": "homeMobileCountryCode"
				}
			],
			"code": 400,
			"message": "Invalid value for UnsignedInteger: "
		}
	}`

	server := mockServer(200, response)
	defer server.Close()
	c, _ := NewClient(WithAPIKey(apiKey))
	c.baseURL = server.URL
	r := &GeolocationRequest{}

	_, err := c.Geolocate(context.Background(), r)
	if err == nil {
		t.Errorf("r.Get returned nil error")
	}

	correctResponse := "Invalid value for UnsignedInteger: "

	if !reflect.DeepEqual(err.Error(), correctResponse) {
		t.Errorf("expected %+v, was %+v", correctResponse, err)
	}
}
<commit_msg>Swapped to old context package<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// More information about Google Geolocation API is available on
// https://developers.google.com/maps/documentation/geolocation

package maps

import (
	"golang.org/x/net/context"
	"reflect"
	"testing"
)

func TestGeolocation(t *testing.T) {

	// Elevation of Denver, the mile high city
	response := `{
		"location" : {
			"lat" : 39.73915360,
			"lng" : -104.98470340
		},
		"accuracy" : 4.771975994110107
	}`

	server := mockServer(200, response)
	defer server.Close()
	c, _ := NewClient(WithAPIKey(apiKey))
	c.baseURL = server.URL
	r := &GeolocationRequest{}

	resp, err := c.Geolocate(context.Background(), r)
	if err != nil {
		t.Errorf("r.Get returned non nil error, was %+v", err)
	}

	correctResponse := GeolocationResult{
		Location: LatLng{
			Lat: 39.73915360,
			Lng: -104.98470340,
		},
		Accuracy: 4.771975994110107,
	}

	if !reflect.DeepEqual(*resp, correctResponse) {
		t.Errorf("expected %+v, was %+v", correctResponse, resp)
	}
}

func TestGeolocationError(t *testing.T) {

	// Elevation of Denver, the mile high city
	response := `{
		"error": {
			"errors": [
				{
					"domain": "global",
					"reason": "invalid",
					"message": "Invalid value for UnsignedInteger: ",
					"locationType": "other",
					"location": "homeMobileCountryCode"
				}
			],
			"code": 400,
			"message": "Invalid value for UnsignedInteger: "
		}
	}`

	server := mockServer(200, response)
	defer server.Close()
	c, _ := NewClient(WithAPIKey(apiKey))
	c.baseURL = server.URL
	r := &GeolocationRequest{}

	_, err := c.Geolocate(context.Background(), r)
	if err == nil {
		t.Errorf("r.Get returned nil error")
	}

	correctResponse := "Invalid value for UnsignedInteger: "

	if !reflect.DeepEqual(err.Error(), correctResponse) {
		t.Errorf("expected %+v, was %+v", correctResponse, err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build darwin,!ios
// +build !js

package graphicscommand

// #cgo CFLAGS: -x objective-c
// #cgo LDFLAGS: -framework Foundation
//
// #import <Foundation/Foundation.h>
//
// static int getDarwinMinorVersion() {
//   NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
//   return (int)version.minorVersion;
// }
import "C"

import (
	"github.com/hajimehoshi/ebiten/internal/graphicsdriver"
	"github.com/hajimehoshi/ebiten/internal/graphicsdriver/metal"
	"github.com/hajimehoshi/ebiten/internal/graphicsdriver/metal/mtl"
	"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl"
)

var (
	// isMetalSupported represents whether Metal is supported.
	isMetalSupported = true

	darwinMajorVersion = 0
)

func init() {
	// On old mac devices like iMac 2011, Metal is not supported (#779).
	if _, err := mtl.CreateSystemDefaultDevice(); err != nil {
		isMetalSupported = false
	}
	// On macOS 10.11 El Capitan, there is a rendering issue on Metal (#781).
	// Use the OpenGL in macOS 10.11 or older.
	if C.getDarwinMinorVersion() <= 11 {
		isMetalSupported = false
	}
}

func Driver() graphicsdriver.GraphicsDriver {
	if isMetalSupported {
		return metal.Get()
	}
	return opengl.Get()
}
<commit_msg>graphicscommand: Rename functions<commit_after>// Copyright 2018 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build darwin,!ios
// +build !js

package graphicscommand

// #cgo CFLAGS: -x objective-c
// #cgo LDFLAGS: -framework Foundation
//
// #import <Foundation/Foundation.h>
//
// static int getMacOSMinorVersion() {
//   NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
//   return (int)version.minorVersion;
// }
import "C"

import (
	"github.com/hajimehoshi/ebiten/internal/graphicsdriver"
	"github.com/hajimehoshi/ebiten/internal/graphicsdriver/metal"
	"github.com/hajimehoshi/ebiten/internal/graphicsdriver/metal/mtl"
	"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl"
)

var (
	// isMetalSupported represents whether Metal is supported.
	isMetalSupported = true
)

func init() {
	// On old mac devices like iMac 2011, Metal is not supported (#779).
	if _, err := mtl.CreateSystemDefaultDevice(); err != nil {
		isMetalSupported = false
	}
	// On macOS 10.11 El Capitan, there is a rendering issue on Metal (#781).
	// Use the OpenGL in macOS 10.11 or older.
	if C.getMacOSMinorVersion() <= 11 {
		isMetalSupported = false
	}
}

func Driver() graphicsdriver.GraphicsDriver {
	if isMetalSupported {
		return metal.Get()
	}
	return opengl.Get()
}
<|endoftext|>


<commit_before>package web

import (
	"net/http"
	"net/url"
	"testing"
	"time"

	"github.com/micro/go-micro/v2/api/resolver"
	"github.com/micro/go-micro/v2/registry"
	"github.com/micro/go-micro/v2/registry/memory"
	"github.com/micro/go-micro/v2/router"
)

func TestWebResolver(t *testing.T) {
	r := memory.NewRegistry()

	res := &Resolver{
		Options: resolver.NewOptions(
			resolver.WithServicePrefix("go.micro.web"),
		),
		Router: router.NewRouter(router.Registry(r)),
	}

	testCases := []struct {
		Host    string
		Path    string
		Service string
	}{
		{"localhost:8082", "/foobar", "go.micro.web.foobar"},
		{"web.micro.mu", "/foobar", "go.micro.web.foobar"},
		{"127.0.0.1:8082", "/hello", "go.micro.web.hello"},
		{"demo.m3o.app", "/bar", "go.micro.web.bar"},
	}

	for _, service := range testCases {
		t.Run(service.Host+service.Path, func(t *testing.T) {
			v := &registry.Service{
				Name:    service.Service,
				Version: "latest",
				Nodes: []*registry.Node{
					{Id: "1", Address: "127.0.0.1:8080"},
				},
			}

			r.Register(v)

			// registry events are published to the router async
			time.Sleep(time.Millisecond * 10)

			u, err := url.Parse("https://" + service.Host + service.Path)
			if err != nil {
				t.Fatal(err)
			}

			req := &http.Request{
				Header: make(http.Header),
				URL:    u,
				Host:   u.Hostname(),
			}
			if endpoint, err := res.Resolve(req); err != nil {
				t.Fatalf("Failed to resolve %v: %v", service, err)
			} else if endpoint.Host != "127.0.0.1:8080" {
				t.Fatalf("Failed to resolve %v", service.Host)
			}

			r.Deregister(v)
		})
	}

}
<commit_msg>internal/resolver/web: disable flakey test<commit_after>package web

import (
	"net/http"
	"net/url"
	"testing"
	"time"

	"github.com/micro/go-micro/v2/api/resolver"
	"github.com/micro/go-micro/v2/registry"
	"github.com/micro/go-micro/v2/registry/memory"
	"github.com/micro/go-micro/v2/router"
)

func TestWebResolver(t *testing.T) {
	r := memory.NewRegistry()

	res := &Resolver{
		Options: resolver.NewOptions(
			resolver.WithServicePrefix("go.micro.web"),
		),
		Router: router.NewRouter(router.Registry(r)),
	}

	testCases := []struct {
		Host    string
		Path    string
		Service string
	}{
		{"localhost:8082", "/foobar", "go.micro.web.foobar"},
		// {"web.micro.mu", "/foobar", "go.micro.web.foobar"},
		{"127.0.0.1:8082", "/hello", "go.micro.web.hello"},
		{"demo.m3o.app", "/bar", "go.micro.web.bar"},
	}

	for _, service := range testCases {
		t.Run(service.Host+service.Path, func(t *testing.T) {
			v := &registry.Service{
				Name:    service.Service,
				Version: "latest",
				Nodes: []*registry.Node{
					{Id: "1", Address: "127.0.0.1:8080"},
				},
			}

			r.Register(v)

			// registry events are published to the router async
			time.Sleep(time.Millisecond * 10)

			u, err := url.Parse("https://" + service.Host + service.Path)
			if err != nil {
				t.Fatal(err)
			}

			req := &http.Request{
				Header: make(http.Header),
				URL:    u,
				Host:   u.Hostname(),
			}
			if endpoint, err := res.Resolve(req); err != nil {
				t.Fatalf("Failed to resolve %v: %v", service, err)
			} else if endpoint.Host != "127.0.0.1:8080" {
				t.Fatalf("Failed to resolve %v", service.Host)
			}

			r.Deregister(v)
		})
	}

}
<|endoftext|>