<commit_before>/* Copyright (C) 2013 Matthias S. Benkmann
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this file (originally named logging.go) and associated documentation files
 * (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is furnished
 * to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package util

import (
         "io"
         "os"
         "fmt"
         "time"
         "sync/atomic"

         "github.com/mbenkmann/golib/deque"
         "github.com/mbenkmann/golib/bytes"
       )

// The loggers used by util.Log().
var loggers deque.Deque
func init() { LoggerAdd(os.Stderr) }

// When the length of the backlog is N times the Backlog factor,
// the LogLevel is reduced by N.
var BacklogFactor = 100

// ATOMIC counter for messages suppressed due to BacklogFactor
var missingMessages int32

// logEntry objects are appended via Push() and the worker goroutine processes entries
// starting At(0). If a log entry is suppressed due to the automatic log rate limitting,
// a nil is queued, so that it is at least recorded that there was supposed to be an
// entry.
var backlog deque.Deque

type logEntry struct {
  Timestamp time.Time
  Format string
  Args []interface{}
}

type Flushable interface {
  Flush() error
}

type Syncable interface {
  Sync() error
}

// Only messages with a level <= this number will be printed.
var LogLevel = 0

// Adds w to the beginning of the list of loggers. Note that any logger that blocks
// during Write() will prevent loggers later in the list from receiving data.
// No checking is done to see if w is already in the list.
// If w == nil, nothing happens.
//
// The most efficient loggers are those that buffer data and support a Flush() or Sync()
// operation (e.g. os.File or bufio.Writer). The background task that writes to
// the loggers will call Flush()/Sync() whenever there is no backlog, so
// even if the logger has a large buffer, data will only be delayed if there is
// a backlog of messages.
func LoggerAdd(w io.Writer) {
  if w != nil { loggers.Insert(w) }
}

// Removes all loggers from the queue that are == to w (if any).
// If w == nil, nothing happens.
func LoggerRemove(w io.Writer) {
  if w != nil { loggers.Remove(w) }
}

// Returns the number of currently active loggers (not counting those
// suspended by LoggersSuspend())
func LoggersCount() int {
  count := 0
  for ; loggers.At(count) != nil; count++ {}
  return count
}

// Disables all loggers currently in the list of loggers until
// LoggersRestore() is called. Loggers added later via LoggerAdd() are
// unaffected, so this call can be used to temporarily switch to
// a different set of loggers.
// Multiple LoggersSuspend()/LoggersRestore() pairs may be nested.
func LoggersSuspend() {
  loggers.Insert(nil)
}

// Restores the loggers list at the most recent LoggersSuspend() call.
// Loggers that were deactivated by LoggersSuspend() are reactivated and
// all loggers added after that call are removed.
//
// ATTENTION! If this function is called without LoggersSuspend() having
// been called first, all loggers will be removed.
func LoggersRestore() {
  for loggers.RemoveAt(0) != nil {}
}

// Does not return until all messages that have accrued up to this point
// have been processed and all loggers that are
// Flushable or Syncable have been flushed/synched.
// Messages that are logged while LoggersFlush() is executing are not
// guaranteed to be logged.
//
// If you pass maxwait != 0, this function will return after at most
// this duration, even if the logs have not been flushed completely
// up to this point.
func LoggersFlush(maxwait time.Duration) {
  // We push TWO dummy entries. The first one already causes a flush,
  // but we need the second to make sure that WaitForEmpty() does not
  // return until the flush is complete.
  backlog.Push(logEntry{})
  backlog.Push(logEntry{})
  backlog.WaitForEmpty(maxwait)
}

// Outputs a message to all loggers added by LoggerAdd() formatted as
// by fmt.Printf().
// The level parameter assigns an importance to the message, where 0
// is the most important (such as fatal errors) and increasing numbers
// mark messages of lesser importance. The idea is that a message of
// level N should only be printed when the program was started with
// N -v (i.e. verbose) switches. So level 0 marks messages that should
// always be logged. Level 1 are informative messages the user may
// not care about. Level 2 and above are typically used for debug
// messages, where level 2 are debug messages that may help the user
// pinpoint a problem and level 3 are debug messages only useful to
// developers. There is usually no need for higher levels.
func Log(level int, format string, args ...interface{}) {
  if (level > LogLevel) { return }
  level_reduce := backlog.Count()/BacklogFactor

  if level > (LogLevel - level_reduce) {
    atomic.AddInt32(&missingMessages, 1)
    return
  }

  entry := logEntry{Timestamp:time.Now(), Format:format, Args:make([]interface{},len(args))}

  for i := range args {
    switch arg := args[i].(type) {
      case string, // for known pass-by-value types, store them directly
           int,uint,uintptr,int8, uint8, int16, uint16, int32, uint32, int64, uint64,
           float32, float64, complex64, complex128,
           time.Time, time.Duration:
           // WARNING! DO NOT ADD []byte or other slices to this case, because
           // the actual logging is done in the background so that the data
           // in the array underlying the slice may have changed when the slice
           // is eventually logged.
        entry.Args[i] = arg
      case io.WriterTo: // special case for *xml.Hash, because it's more efficient to use WriteTo()
        buf := new(bytes.Buffer)
        _, err := arg.WriteTo(buf)
        if err != nil {
          buf.Reset()
          entry.Args[i] = fmt.Sprintf("%v", arg)
        } else {
          entry.Args[i] = buf
        }
      default: // for unknown types, transform them to a string with %v format
        entry.Args[i] = fmt.Sprintf("%v", arg)
    }
  }

  backlog.Push(entry)
}

// infinite loop that processes backlog and writes it to all loggers.
func writeLogsLoop() {
  for {
    if backlog.IsEmpty() {
      m := atomic.LoadInt32(&missingMessages)
      if m > 0 {
        writeLogEntry(logEntry{Timestamp:time.Now(), Format:"%d %s", Args:[]interface{}{m,"missing message(s)"}})
        atomic.AddInt32(&missingMessages, -m)
      }
      flushLogs()
    }

    entry := backlog.Next().(logEntry)
    if entry.Args == nil { flushLogs() } else { writeLogEntry(entry) }
  }
}
func init() { go writeLogsLoop() }

// Writes entry to all loggers.
func writeLogEntry(entry logEntry) {
  buf := new(bytes.Buffer)
  defer buf.Reset()

  t := entry.Timestamp
  fmt.Fprintf(buf, "%d-%02d-%02d %02d:%02d:%02d ",
      t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())

  fmt.Fprintf(buf, entry.Format, entry.Args...)

  // free all buffers created by Log()
  for i := range entry.Args {
    if b, isbuf := entry.Args[i].(*bytes.Buffer); isbuf {
      b.Reset()
    }
  }

  buf.WriteByte('\n')
  writeToAllLogs(buf.Bytes())
}

// Writes data to all elements of loggers up to the first nil entry (which is
// a mark inserted by LoggersSuspend().
func writeToAllLogs(data []byte) {
  for i:=0; i < loggers.Count(); i++ {
    logger := loggers.At(i)
    if logger == nil { break }
    WriteAll(logger.(io.Writer), data)
  }
}

// Calls Flush() for all loggers that are Flushable and Sync() for all loggers
// that are Syncable (unless they are also Flushable).
// The loggers list is processed up to the first nil entry
// (see writeToAlllogs).
func flushLogs() {
  for i:=0; i < loggers.Count(); i++ {
    logger := loggers.At(i)
    if logger == nil { break }
    if flush, flushable := logger.(Flushable); flushable {
      flush.Flush()
    } else if syn, syncable := logger.(Syncable); syncable {
      syn.Sync()
    }
  }
}

// Returns a io.WriteCloser that appends to the file fpath, checking on each
// write if fpath still refers to the same file and if it doesn't re-opens or
// re-creates the file fpath
// to append to. This behaviour is compatible with log-rotation without
// incurring the overhead of re-opening the file on every write.
//
// NOTE: While closing the returned object will close the underlying file
// if it is open, it will not invalidate the object. The next write will
// open the file again (creating it if necessary) and will append to it.
func LogFile(fpath string) io.WriteCloser {
  return &logFile{path:fpath}
}

type logFile struct {
  path string
  file *os.File
  fi os.FileInfo
}

func (f *logFile) Close() error {
  if f.file == nil { return nil }
  err := f.file.Close()
  f.file = nil
  f.fi = nil
  return err
}

func (f *logFile) Write(p []byte) (n int, err error) {
  if f.file != nil { // if we have an open file
    fi2, err := os.Stat(f.path)
    if err != nil || !os.SameFile(f.fi,fi2) { // if statting the path failed or file has changed => close old and re-open/create
      f.file.Close()
      f.file, err = os.OpenFile(f.path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
      if err != nil { return 0,err }
      f.fi, err = f.file.Stat()
      if err != nil { return 0,err }
    }
  } else { // if we don't have an open file => create a new one
    f.file, err = os.OpenFile(f.path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
    if err != nil { return 0,err }
    f.fi, err = f.file.Stat()
    if err != nil { return 0,err }
  }

  return f.file.Write(p)
}
<commit_msg>fix import path<commit_after>/* Copyright (C) 2013 Matthias S. Benkmann
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this file (originally named logging.go) and associated documentation files
 * (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is furnished
 * to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package util

import (
         "io"
         "os"
         "fmt"
         "time"
         "sync/atomic"

         "winterdrache.de/golib/deque"
         "winterdrache.de/golib/bytes"
       )

// The loggers used by util.Log().
var loggers deque.Deque
func init() { LoggerAdd(os.Stderr) }

// When the length of the backlog is N times the Backlog factor,
// the LogLevel is reduced by N.
var BacklogFactor = 100

// ATOMIC counter for messages suppressed due to BacklogFactor
var missingMessages int32

// logEntry objects are appended via Push() and the worker goroutine processes entries
// starting At(0). If a log entry is suppressed due to the automatic log rate limitting,
// a nil is queued, so that it is at least recorded that there was supposed to be an
// entry.
var backlog deque.Deque

type logEntry struct {
  Timestamp time.Time
  Format string
  Args []interface{}
}

type Flushable interface {
  Flush() error
}

type Syncable interface {
  Sync() error
}

// Only messages with a level <= this number will be printed.
var LogLevel = 0

// Adds w to the beginning of the list of loggers. Note that any logger that blocks
// during Write() will prevent loggers later in the list from receiving data.
// No checking is done to see if w is already in the list.
// If w == nil, nothing happens.
//
// The most efficient loggers are those that buffer data and support a Flush() or Sync()
// operation (e.g. os.File or bufio.Writer). The background task that writes to
// the loggers will call Flush()/Sync() whenever there is no backlog, so
// even if the logger has a large buffer, data will only be delayed if there is
// a backlog of messages.
func LoggerAdd(w io.Writer) {
  if w != nil { loggers.Insert(w) }
}

// Removes all loggers from the queue that are == to w (if any).
// If w == nil, nothing happens.
func LoggerRemove(w io.Writer) {
  if w != nil { loggers.Remove(w) }
}

// Returns the number of currently active loggers (not counting those
// suspended by LoggersSuspend())
func LoggersCount() int {
  count := 0
  for ; loggers.At(count) != nil; count++ {}
  return count
}

// Disables all loggers currently in the list of loggers until
// LoggersRestore() is called. Loggers added later via LoggerAdd() are
// unaffected, so this call can be used to temporarily switch to
// a different set of loggers.
// Multiple LoggersSuspend()/LoggersRestore() pairs may be nested.
func LoggersSuspend() {
  loggers.Insert(nil)
}

// Restores the loggers list at the most recent LoggersSuspend() call.
// Loggers that were deactivated by LoggersSuspend() are reactivated and
// all loggers added after that call are removed.
//
// ATTENTION! If this function is called without LoggersSuspend() having
// been called first, all loggers will be removed.
func LoggersRestore() {
  for loggers.RemoveAt(0) != nil {}
}

// Does not return until all messages that have accrued up to this point
// have been processed and all loggers that are
// Flushable or Syncable have been flushed/synched.
// Messages that are logged while LoggersFlush() is executing are not
// guaranteed to be logged.
//
// If you pass maxwait != 0, this function will return after at most
// this duration, even if the logs have not been flushed completely
// up to this point.
func LoggersFlush(maxwait time.Duration) {
  // We push TWO dummy entries. The first one already causes a flush,
  // but we need the second to make sure that WaitForEmpty() does not
  // return until the flush is complete.
  backlog.Push(logEntry{})
  backlog.Push(logEntry{})
  backlog.WaitForEmpty(maxwait)
}

// Outputs a message to all loggers added by LoggerAdd() formatted as
// by fmt.Printf().
// The level parameter assigns an importance to the message, where 0
// is the most important (such as fatal errors) and increasing numbers
// mark messages of lesser importance. The idea is that a message of
// level N should only be printed when the program was started with
// N -v (i.e. verbose) switches. So level 0 marks messages that should
// always be logged. Level 1 are informative messages the user may
// not care about. Level 2 and above are typically used for debug
// messages, where level 2 are debug messages that may help the user
// pinpoint a problem and level 3 are debug messages only useful to
// developers. There is usually no need for higher levels.
func Log(level int, format string, args ...interface{}) {
  if (level > LogLevel) { return }
  level_reduce := backlog.Count()/BacklogFactor

  if level > (LogLevel - level_reduce) {
    atomic.AddInt32(&missingMessages, 1)
    return
  }

  entry := logEntry{Timestamp:time.Now(), Format:format, Args:make([]interface{},len(args))}

  for i := range args {
    switch arg := args[i].(type) {
      case string, // for known pass-by-value types, store them directly
           int,uint,uintptr,int8, uint8, int16, uint16, int32, uint32, int64, uint64,
           float32, float64, complex64, complex128,
           time.Time, time.Duration:
           // WARNING! DO NOT ADD []byte or other slices to this case, because
           // the actual logging is done in the background so that the data
           // in the array underlying the slice may have changed when the slice
           // is eventually logged.
        entry.Args[i] = arg
      case io.WriterTo: // special case for *xml.Hash, because it's more efficient to use WriteTo()
        buf := new(bytes.Buffer)
        _, err := arg.WriteTo(buf)
        if err != nil {
          buf.Reset()
          entry.Args[i] = fmt.Sprintf("%v", arg)
        } else {
          entry.Args[i] = buf
        }
      default: // for unknown types, transform them to a string with %v format
        entry.Args[i] = fmt.Sprintf("%v", arg)
    }
  }

  backlog.Push(entry)
}

// infinite loop that processes backlog and writes it to all loggers.
func writeLogsLoop() {
  for {
    if backlog.IsEmpty() {
      m := atomic.LoadInt32(&missingMessages)
      if m > 0 {
        writeLogEntry(logEntry{Timestamp:time.Now(), Format:"%d %s", Args:[]interface{}{m,"missing message(s)"}})
        atomic.AddInt32(&missingMessages, -m)
      }
      flushLogs()
    }

    entry := backlog.Next().(logEntry)
    if entry.Args == nil { flushLogs() } else { writeLogEntry(entry) }
  }
}
func init() { go writeLogsLoop() }

// Writes entry to all loggers.
func writeLogEntry(entry logEntry) {
  buf := new(bytes.Buffer)
  defer buf.Reset()

  t := entry.Timestamp
  fmt.Fprintf(buf, "%d-%02d-%02d %02d:%02d:%02d ",
      t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())

  fmt.Fprintf(buf, entry.Format, entry.Args...)

  // free all buffers created by Log()
  for i := range entry.Args {
    if b, isbuf := entry.Args[i].(*bytes.Buffer); isbuf {
      b.Reset()
    }
  }

  buf.WriteByte('\n')
  writeToAllLogs(buf.Bytes())
}

// Writes data to all elements of loggers up to the first nil entry (which is
// a mark inserted by LoggersSuspend().
func writeToAllLogs(data []byte) {
  for i:=0; i < loggers.Count(); i++ {
    logger := loggers.At(i)
    if logger == nil { break }
    WriteAll(logger.(io.Writer), data)
  }
}

// Calls Flush() for all loggers that are Flushable and Sync() for all loggers
// that are Syncable (unless they are also Flushable).
// The loggers list is processed up to the first nil entry
// (see writeToAlllogs).
func flushLogs() {
  for i:=0; i < loggers.Count(); i++ {
    logger := loggers.At(i)
    if logger == nil { break }
    if flush, flushable := logger.(Flushable); flushable {
      flush.Flush()
    } else if syn, syncable := logger.(Syncable); syncable {
      syn.Sync()
    }
  }
}

// Returns a io.WriteCloser that appends to the file fpath, checking on each
// write if fpath still refers to the same file and if it doesn't re-opens or
// re-creates the file fpath
// to append to. This behaviour is compatible with log-rotation without
// incurring the overhead of re-opening the file on every write.
//
// NOTE: While closing the returned object will close the underlying file
// if it is open, it will not invalidate the object. The next write will
// open the file again (creating it if necessary) and will append to it.
func LogFile(fpath string) io.WriteCloser {
  return &logFile{path:fpath}
}

type logFile struct {
  path string
  file *os.File
  fi os.FileInfo
}

func (f *logFile) Close() error {
  if f.file == nil { return nil }
  err := f.file.Close()
  f.file = nil
  f.fi = nil
  return err
}

func (f *logFile) Write(p []byte) (n int, err error) {
  if f.file != nil { // if we have an open file
    fi2, err := os.Stat(f.path)
    if err != nil || !os.SameFile(f.fi,fi2) { // if statting the path failed or file has changed => close old and re-open/create
      f.file.Close()
      f.file, err = os.OpenFile(f.path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
      if err != nil { return 0,err }
      f.fi, err = f.file.Stat()
      if err != nil { return 0,err }
    }
  } else { // if we don't have an open file => create a new one
    f.file, err = os.OpenFile(f.path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
    if err != nil { return 0,err }
    f.fi, err = f.file.Stat()
    if err != nil { return 0,err }
  }

  return f.file.Write(p)
}
<|endoftext|>


<commit_before>package utils

import (
	"bytes"
)

// ClosingBuffer implement Closer interface for Buffer
type ClosingBuffer struct {
	*bytes.Buffer
}

// Close implement Closer interface for Buffer
func (ClosingBuffer) Close() error {
	return nil
}
<commit_msg>Apply Close method for ReadSeeker<commit_after>package utils

import "io"

// ClosingReadSeeker implement Closer interface for ReadSeeker
type ClosingReadSeeker struct {
	io.ReadSeeker
}

// Close implement Closer interface for Buffer
func (ClosingReadSeeker) Close() error {
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"github.com/golang/groupcache"
	"github.com/gorilla/mux"
	"image"
	"io"
	"math/rand"
	"net/http"
	"os"
	"time"
	"vip/fetch"
)

type UploadResponse struct {
	Url string `json:"url"`
}

type ErrorResponse struct {
	Msg string `json:"error"`
}

type verifyAuth func(http.ResponseWriter, *http.Request)

func (h verifyAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Enable cross-origin requests
	if domain := os.Getenv("ALLOWED_ORIGIN"); domain != "" {
		if origin := r.Header.Get("Origin"); origin == domain {
			w.Header().Set("Access-Control-Allow-Origin", origin)
			w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
			w.Header().Set("Access-Control-Allow-Headers",
				"Accept, Content-Type, Content-Length, Accept-Encoding, X-Vip-Token, Authorization")
		}
	} else {
		auth := r.Header.Get("X-Vip-Token")
		if auth != authToken {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}
	}

	if r.Method == "OPTIONS" {
		return
	}

	h(w, r)
}

func fileKey(bucket string, width int, height int) string {
	seed := rand.New(rand.NewSource(time.Now().UnixNano()))
	key := fmt.Sprintf("%d-%s-%d", seed.Int63(), bucket, time.Now().UnixNano())

	hash := md5.New()
	io.WriteString(hash, key)
	return fmt.Sprintf("%x-%dx%d", hash.Sum(nil), width, height)
}

func handleImageRequest(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		w.WriteHeader(http.StatusMethodNotAllowed)
	}

	w.Header().Set("Cache-Control", "public, max-age=31536000")

	// Client is checking for a cached URI, assume it is valid
	// and return a 304
	if r.Header.Get("If-Modified-Since") != "" {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	gc := fetch.RequestContext(r)

	var data []byte
	err := cache.Get(gc, gc.CacheKey(), groupcache.AllocatingByteSliceSink(&data))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	w.Header().Set("Content-Type", http.DetectContentType(data))
	http.ServeContent(w, r, gc.ImageId, time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), bytes.NewReader(data))
}

func handleUpload(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	vars := mux.Vars(r)
	bucket := vars["bucket_id"]

	// Set a hard limit in MB on files
	var limit int64 = 5
	if r.ContentLength > limit<<20 {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusRequestEntityTooLarge)
		json.NewEncoder(w).Encode(ErrorResponse{
			Msg: fmt.Sprintf("The file size limit is %dMB", limit),
		})
		return
	}

	raw, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	data := bytes.NewReader(raw)

	image, format, err := image.Decode(data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	width := image.Bounds().Size().X
	height := image.Bounds().Size().Y

	key := fileKey(bucket, width, height)

	data.Seek(0, 0)

	err = storage.PutReader(bucket, key, data,
		r.ContentLength, r.Header.Get("Content-Type"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer r.Body.Close()

	uri := r.URL

	if r.URL.Host == "" {
		uri.Host = os.Getenv("URI_HOSTNAME")
		if secure {
			uri.Scheme = "https"
		} else {
			uri.Scheme = "http"
		}
	}

	uri.Path = fmt.Sprintf("%s/%s", bucket, key)

	w.Header().Set("Content-Type", "application/json")

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(UploadResponse{
		Url: uri.String(),
	})
}

func handlePing(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "pong")
}
<commit_msg>import<commit_after>package main

import (
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"github.com/golang/groupcache"
	"github.com/gorilla/mux"
	"image"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"time"
	"vip/fetch"
)

type UploadResponse struct {
	Url string `json:"url"`
}

type ErrorResponse struct {
	Msg string `json:"error"`
}

type verifyAuth func(http.ResponseWriter, *http.Request)

func (h verifyAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Enable cross-origin requests
	if domain := os.Getenv("ALLOWED_ORIGIN"); domain != "" {
		if origin := r.Header.Get("Origin"); origin == domain {
			w.Header().Set("Access-Control-Allow-Origin", origin)
			w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
			w.Header().Set("Access-Control-Allow-Headers",
				"Accept, Content-Type, Content-Length, Accept-Encoding, X-Vip-Token, Authorization")
		}
	} else {
		auth := r.Header.Get("X-Vip-Token")
		if auth != authToken {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}
	}

	if r.Method == "OPTIONS" {
		return
	}

	h(w, r)
}

func fileKey(bucket string, width int, height int) string {
	seed := rand.New(rand.NewSource(time.Now().UnixNano()))
	key := fmt.Sprintf("%d-%s-%d", seed.Int63(), bucket, time.Now().UnixNano())

	hash := md5.New()
	io.WriteString(hash, key)
	return fmt.Sprintf("%x-%dx%d", hash.Sum(nil), width, height)
}

func handleImageRequest(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		w.WriteHeader(http.StatusMethodNotAllowed)
	}

	w.Header().Set("Cache-Control", "public, max-age=31536000")

	// Client is checking for a cached URI, assume it is valid
	// and return a 304
	if r.Header.Get("If-Modified-Since") != "" {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	gc := fetch.RequestContext(r)

	var data []byte
	err := cache.Get(gc, gc.CacheKey(), groupcache.AllocatingByteSliceSink(&data))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	w.Header().Set("Content-Type", http.DetectContentType(data))
	http.ServeContent(w, r, gc.ImageId, time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), bytes.NewReader(data))
}

func handleUpload(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	vars := mux.Vars(r)
	bucket := vars["bucket_id"]

	// Set a hard limit in MB on files
	var limit int64 = 5
	if r.ContentLength > limit<<20 {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusRequestEntityTooLarge)
		json.NewEncoder(w).Encode(ErrorResponse{
			Msg: fmt.Sprintf("The file size limit is %dMB", limit),
		})
		return
	}

	raw, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	data := bytes.NewReader(raw)

	image, format, err := image.Decode(data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	width := image.Bounds().Size().X
	height := image.Bounds().Size().Y

	key := fileKey(bucket, width, height)

	data.Seek(0, 0)

	err = storage.PutReader(bucket, key, data,
		r.ContentLength, r.Header.Get("Content-Type"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer r.Body.Close()

	uri := r.URL

	if r.URL.Host == "" {
		uri.Host = os.Getenv("URI_HOSTNAME")
		if secure {
			uri.Scheme = "https"
		} else {
			uri.Scheme = "http"
		}
	}

	uri.Path = fmt.Sprintf("%s/%s", bucket, key)

	w.Header().Set("Content-Type", "application/json")

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(UploadResponse{
		Url: uri.String(),
	})
}

func handlePing(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "pong")
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"github.com/golang/groupcache"
	"github.com/gorilla/mux"
	"image"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"time"
	"vip/fetch"
)

type UploadResponse struct {
	Url string `json:"url"`
}

type ErrorResponse struct {
	Msg string `json:"error"`
}

type verifyAuth func(http.ResponseWriter, *http.Request)

func (h verifyAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Enable cross-origin requests
	if domain := os.Getenv("ALLOWED_ORIGIN"); domain != "" {
		if origin := r.Header.Get("Origin"); origin == domain {
			w.Header().Set("Access-Control-Allow-Origin", origin)
			w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
			w.Header().Set("Access-Control-Allow-Headers",
				"Accept, Content-Type, Content-Length, Accept-Encoding, X-Vip-Token, Authorization")
		}
	} else {
		auth := r.Header.Get("X-Vip-Token")
		if auth != authToken {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}
	}

	if r.Method == "OPTIONS" {
		return
	}

	h(w, r)
}

func fileKey(bucket string, width int, height int) string {
	seed := rand.New(rand.NewSource(time.Now().UnixNano()))
	key := fmt.Sprintf("%d-%s-%d", seed.Int63(), bucket, time.Now().UnixNano())

	hash := md5.New()
	io.WriteString(hash, key)
	return fmt.Sprintf("%x-%dx%d", hash.Sum(nil), width, height)
}

func handleImageRequest(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		w.WriteHeader(http.StatusMethodNotAllowed)
	}

	w.Header().Set("Cache-Control", "public, max-age=31536000")

	// Client is checking for a cached URI, assume it is valid
	// and return a 304
	if r.Header.Get("If-Modified-Since") != "" {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	gc := fetch.RequestContext(r)

	var data []byte
	err := cache.Get(gc, gc.CacheKey(), groupcache.AllocatingByteSliceSink(&data))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	w.Header().Set("Content-Type", http.DetectContentType(data))
	http.ServeContent(w, r, gc.ImageId, time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), bytes.NewReader(data))
}

func handleUpload(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	vars := mux.Vars(r)
	bucket := vars["bucket_id"]
	// Set a hard limit in MB on files
	var limit int64 = 5
	if r.ContentLength > limit<<20 {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusRequestEntityTooLarge)
		json.NewEncoder(w).Encode(ErrorResponse{
			Msg: fmt.Sprintf("The file size limit is %dMB", limit),
		})
		return
	} else if r.ContentLength == 0 {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(ErrorResponse{
			Msg: fmt.Sprintf("File must have size greater than 0"),
		})
		return
	}

	raw, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	r.Body.Close()

	data := bytes.NewReader(raw)

	image, _, err := image.Decode(data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	width := image.Bounds().Size().X
	height := image.Bounds().Size().Y

	key := fileKey(bucket, width, height)

	data.Seek(0, 0)

	err = storage.PutReader(bucket, key, data,
		r.ContentLength, r.Header.Get("Content-Type"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	uri := r.URL

	if r.URL.Host == "" {
		uri.Host = os.Getenv("URI_HOSTNAME")
		if secure {
			uri.Scheme = "https"
		} else {
			uri.Scheme = "http"
		}
	}

	uri.Path = fmt.Sprintf("%s/%s", bucket, key)

	w.Header().Set("Content-Type", "application/json")

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(UploadResponse{
		Url: uri.String(),
	})
}

func handlePing(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "pong")
}
<commit_msg>Move rotation to file upload<commit_after>package main

import (
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"github.com/golang/groupcache"
	"github.com/gorilla/mux"
	"image"
	"image/jpeg"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"time"
	"vip/fetch"
)

type UploadResponse struct {
	Url string `json:"url"`
}

type ErrorResponse struct {
	Msg string `json:"error"`
}

type verifyAuth func(http.ResponseWriter, *http.Request)

func (h verifyAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Enable cross-origin requests
	if domain := os.Getenv("ALLOWED_ORIGIN"); domain != "" {
		if origin := r.Header.Get("Origin"); origin == domain {
			w.Header().Set("Access-Control-Allow-Origin", origin)
			w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
			w.Header().Set("Access-Control-Allow-Headers",
				"Accept, Content-Type, Content-Length, Accept-Encoding, X-Vip-Token, Authorization")
		}
	} else {
		auth := r.Header.Get("X-Vip-Token")
		if auth != authToken {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}
	}

	if r.Method == "OPTIONS" {
		return
	}

	h(w, r)
}

func fileKey(bucket string, width int, height int) string {
	seed := rand.New(rand.NewSource(time.Now().UnixNano()))
	key := fmt.Sprintf("%d-%s-%d", seed.Int63(), bucket, time.Now().UnixNano())

	hash := md5.New()
	io.WriteString(hash, key)
	return fmt.Sprintf("%x-%dx%d", hash.Sum(nil), width, height)
}

func handleImageRequest(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		w.WriteHeader(http.StatusMethodNotAllowed)
	}

	w.Header().Set("Cache-Control", "public, max-age=31536000")

	// Client is checking for a cached URI, assume it is valid
	// and return a 304
	if r.Header.Get("If-Modified-Since") != "" {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	gc := fetch.RequestContext(r)

	var data []byte
	err := cache.Get(gc, gc.CacheKey(), groupcache.AllocatingByteSliceSink(&data))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	w.Header().Set("Content-Type", http.DetectContentType(data))
	http.ServeContent(w, r, gc.ImageId, time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), bytes.NewReader(data))
}

func handleUpload(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	vars := mux.Vars(r)
	bucket := vars["bucket_id"]
	// Set a hard limit in MB on files
	var limit int64 = 5
	if r.ContentLength > limit<<20 {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusRequestEntityTooLarge)
		json.NewEncoder(w).Encode(ErrorResponse{
			Msg: fmt.Sprintf("The file size limit is %dMB", limit),
		})
		return
	} else if r.ContentLength == 0 {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(ErrorResponse{
			Msg: fmt.Sprintf("File must have size greater than 0"),
		})
		return
	}

	mime := r.Header.Get("Content-Type")

	data, key, err := processFile(r.Body, mime)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	r.Body.Close()

	err = storage.PutReader(bucket, key, data,
		r.ContentLength, r.Header.Get("Content-Type"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	uri := r.URL

	if r.URL.Host == "" {
		uri.Host = os.Getenv("URI_HOSTNAME")
		if secure {
			uri.Scheme = "https"
		} else {
			uri.Scheme = "http"
		}
	}

	uri.Path = fmt.Sprintf("%s/%s", bucket, key)

	w.Header().Set("Content-Type", "application/json")

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(UploadResponse{
		Url: uri.String(),
	})
}

func handlePing(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "pong")
}

func processFile(src io.Reader, mime string) (out io.Reader, key string, err err) {
	if mime == "image/jpeg" {
		image, format, err := fetch.GetRotatedImage(src)
		if err != nil {
			return nil, "", err
		}

		width := image.Bounds().Size().X
		height := image.Bounds().Size().Y
		key := fileKey(bucket, width, height)

		data := new(bytes.Buffer)
		err = jpeg.Encode(data, image, nil)
		if err != nil {
			return nil, "", err
		}

		return data, key, nil

	} else {
		raw, err := ioutil.ReadAll(src)
		if err != nil {
			return nil, "", err
		}

		data := bytes.NewReader(raw)
		image, _, err := image.Decode(data)
		if err != nil {
			return nil, "", err
		}

		width := image.Bounds().Size().X
		height := image.Bounds().Size().Y
		key := fileKey(bucket, width, height)

		data.Seek(0, 0)

		return data, key, nil
	}
}
<|endoftext|>


<commit_before>// Package nosurf implements an HTTP handler that
// mitigates Cross-Site Request Forgery Attacks.
package nosurf

import (
	"net/http"
	"regexp"
)

const (
	// the name of CSRF cookie
	CookieName = "csrf_token"
	// the name of the form field
	FormFieldName = "csrf_token"
	// the name of CSRF header
	HeaderName = "X-CSRF-Token"
	// the HTTP status code for the default failure handler
	FailureCode = 400

	// Max-Age for the default base cookie. 365 days.
	DefaultMaxAge = 365 * 24 * 60 * 60
)

var safeMethods = []string{"GET", "HEAD", "OPTIONS", "TRACE"}

type CSRFHandler struct {
	// Handlers that CSRFHandler wraps.
	successHandler http.Handler
	failureHandler http.Handler

	// The base cookie that CSRF cookies will be built upon.
	// This should be a better solution of customizing the options
	// than a bunch of methods SetCookieExpiration(), etc.
	baseCookie http.Cookie

	// Slices of paths that are exempt from CSRF checks.
	// They can be specified by...
	// ...an exact path,
	exemptPaths []string
	// ...a regexp,
	exemptRegexps []*regexp.Regexp
	// ...or a glob (as used by path.Match()).
	exemptGlobs []string

	// All of those will be matched against Request.URL.Path,
	// So they should take the leading slash into account
}

func defaultFailureHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(FailureCode)
}

// Constructs a new CSRFHandler that calls
// the specified handler if the CSRF check succeeds.
func New(handler http.Handler) *CSRFHandler {
	baseCookie := http.Cookie{}
	baseCookie.MaxAge = DefaultMaxAge

	csrf := &CSRFHandler{successHandler: handler,
		failureHandler: http.HandlerFunc(defaultFailureHandler),
		exemptPaths:    make([]string, 0),
		exemptGlobs:    make([]string, 0),
		exemptRegexps:  make([]*regexp.Regexp, 0),
		baseCookie:     baseCookie,
	}

	return csrf
}

func (h *CSRFHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Prefer the header over form value
	sent_token := r.Header.Get(HeaderName)
	if sent_token == "" {
		sent_token = r.PostFormValue(FormFieldName)
	}

	token_cookie, err := r.Cookie(CookieName)
	real_token := ""
	if err == http.ErrNoCookie {
		real_token = h.RegenerateToken(w, r)
	} else {
		real_token = token_cookie.Value
	}
	// If the length of the real token isn't what it should be,
	// it has either been tampered with,
	// or we're migrating onto a new algorithm for generating tokens.
	// In any case of those, we should regenerate it.
	if len(real_token) != tokenLength {
		real_token = h.RegenerateToken(w, r)
	}

	// clear the context after the request is served
	defer ctxClear(r)
	ctxSetToken(r, real_token)

	if sContains(safeMethods, r.Method) {
		// short-circuit with a success for safe methods
		h.handleSuccess(w, r)
		return
	}
}

// handleSuccess simply calls the successHandler
// everything else, like setting a token in the context
// is taken care of by h.ServeHTTP()
func (h *CSRFHandler) handleSuccess(w http.ResponseWriter, r *http.Request) {
	h.successHandler.ServeHTTP(w, r)
}

// Same applies here: h.ServeHTTP() sets the failure reason, the token,
// and only then calls handleFailure()
func (h *CSRFHandler) handleFailure(w http.ResponseWriter, r *http.Request) {
	h.failureHandler.ServeHTTP(w, r)
}

// Generates a new token, sets it on the given request and returns it
func (h *CSRFHandler) RegenerateToken(w http.ResponseWriter, r *http.Request) string {
	token := generateToken()
	h.setTokenCookie(w, r, token)

	return token
}

func (h *CSRFHandler) setTokenCookie(w http.ResponseWriter, r *http.Request, token string) {
	cookie := h.baseCookie
	cookie.Name = CookieName
	cookie.Value = token

	http.SetCookie(w, &cookie)

	ctxSetToken(r, token)
}

// Sets the handler to call in case the CSRF check
// fails. By default it's defaultFailureHandler.
func (h *CSRFHandler) SetFailureHandler(handler http.Handler) {
	h.failureHandler = handler
}

// Sets the base cookie to use when building a CSRF token cookie
// This way you can specify the Domain, Path, HttpOnly, Secure, etc.
func (h *CSRFHandler) SetBaseCookie(cookie http.Cookie) {
	h.baseCookie = cookie
}
<commit_msg>Renew the cookie on success<commit_after>// Package nosurf implements an HTTP handler that
// mitigates Cross-Site Request Forgery Attacks.
package nosurf

import (
	"net/http"
	"regexp"
)

const (
	// the name of CSRF cookie
	CookieName = "csrf_token"
	// the name of the form field
	FormFieldName = "csrf_token"
	// the name of CSRF header
	HeaderName = "X-CSRF-Token"
	// the HTTP status code for the default failure handler
	FailureCode = 400

	// Max-Age for the default base cookie. 365 days.
	DefaultMaxAge = 365 * 24 * 60 * 60
)

var safeMethods = []string{"GET", "HEAD", "OPTIONS", "TRACE"}

type CSRFHandler struct {
	// Handlers that CSRFHandler wraps.
	successHandler http.Handler
	failureHandler http.Handler

	// The base cookie that CSRF cookies will be built upon.
	// This should be a better solution of customizing the options
	// than a bunch of methods SetCookieExpiration(), etc.
	baseCookie http.Cookie

	// Slices of paths that are exempt from CSRF checks.
	// They can be specified by...
	// ...an exact path,
	exemptPaths []string
	// ...a regexp,
	exemptRegexps []*regexp.Regexp
	// ...or a glob (as used by path.Match()).
	exemptGlobs []string

	// All of those will be matched against Request.URL.Path,
	// So they should take the leading slash into account
}

func defaultFailureHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(FailureCode)
}

// Constructs a new CSRFHandler that calls
// the specified handler if the CSRF check succeeds.
func New(handler http.Handler) *CSRFHandler {
	baseCookie := http.Cookie{}
	baseCookie.MaxAge = DefaultMaxAge

	csrf := &CSRFHandler{successHandler: handler,
		failureHandler: http.HandlerFunc(defaultFailureHandler),
		exemptPaths:    make([]string, 0),
		exemptGlobs:    make([]string, 0),
		exemptRegexps:  make([]*regexp.Regexp, 0),
		baseCookie:     baseCookie,
	}

	return csrf
}

func (h *CSRFHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Prefer the header over form value
	sent_token := r.Header.Get(HeaderName)
	if sent_token == "" {
		sent_token = r.PostFormValue(FormFieldName)
	}

	token_cookie, err := r.Cookie(CookieName)
	real_token := ""
	if err == http.ErrNoCookie {
		real_token = h.RegenerateToken(w, r)
	} else {
		real_token = token_cookie.Value
	}
	// If the length of the real token isn't what it should be,
	// it has either been tampered with,
	// or we're migrating onto a new algorithm for generating tokens.
	// In any case of those, we should regenerate it.
	if len(real_token) != tokenLength {
		real_token = h.RegenerateToken(w, r)
	}

	// clear the context after the request is served
	defer ctxClear(r)
	ctxSetToken(r, real_token)

	if sContains(safeMethods, r.Method) {
		// short-circuit with a success for safe methods
		h.handleSuccess(w, r)
		return
	}
}

// handleSuccess simply calls the successHandler
// everything else, like setting a token in the context
// is taken care of by h.ServeHTTP()
func (h *CSRFHandler) handleSuccess(w http.ResponseWriter, r *http.Request) {
	// On a successful check, we might as well renew the cookie.
	token := Token(r)
	h.setTokenCookie(w, r, token)

	h.successHandler.ServeHTTP(w, r)
}

// Same applies here: h.ServeHTTP() sets the failure reason, the token,
// and only then calls handleFailure()
func (h *CSRFHandler) handleFailure(w http.ResponseWriter, r *http.Request) {
	h.failureHandler.ServeHTTP(w, r)
}

// Generates a new token, sets it on the given request and returns it
func (h *CSRFHandler) RegenerateToken(w http.ResponseWriter, r *http.Request) string {
	token := generateToken()
	h.setTokenCookie(w, r, token)

	return token
}

func (h *CSRFHandler) setTokenCookie(w http.ResponseWriter, r *http.Request, token string) {
	cookie := h.baseCookie
	cookie.Name = CookieName
	cookie.Value = token

	http.SetCookie(w, &cookie)

	ctxSetToken(r, token)
}

// Sets the handler to call in case the CSRF check
// fails. By default it's defaultFailureHandler.
func (h *CSRFHandler) SetFailureHandler(handler http.Handler) {
	h.failureHandler = handler
}

// Sets the base cookie to use when building a CSRF token cookie
// This way you can specify the Domain, Path, HttpOnly, Secure, etc.
func (h *CSRFHandler) SetBaseCookie(cookie http.Cookie) {
	h.baseCookie = cookie
}
<|endoftext|>


<commit_before>// Possum is a micro web-api framework for Go.
package possum

import (
	"encoding/json"
	"fmt"
	"net/http"
)

const (
	GET    = "GET"
	POST   = "POST"
	PUT    = "PUT"
	DELETE = "DELETE"
	PATCH  = "PATCH"
)

// Processing function returning HTTP status code and response object witch will be marshaled to JSON.
type HandlerFunc func(w http.ResponseWriter, r *http.Request) (int, interface{})

type (
	// Interface for handling GET request.
	Get interface {
		Get(w http.ResponseWriter, r *http.Request) (int, interface{})
	}
	// Interface for handling PUT request.
	Put interface {
		Put(w http.ResponseWriter, r *http.Request) (int, interface{})
	}
	// Interface for handling POST request.
	Post interface {
		Post(w http.ResponseWriter, r *http.Request) (int, interface{})
	}
	// Interface for handling DELETE request.
	Delete interface {
		Delete(w http.ResponseWriter, r *http.Request) (int, interface{})
	}
	// Interface for handling PATCH request.
	Patch interface {
		Patch(w http.ResponseWriter, r *http.Request) (int, interface{})
	}
)

// Objects implementing the Get interface response status NotImplemented(501).
type NoGet struct{}

func (NoGet) Get(w http.ResponseWriter, r *http.Request) (int, interface{}) {
	return http.StatusNotImplemented, "GET is not supported"
}

// Objects implementing the Post interface response status NotImplemented(501).
type NoPost struct{}

func (NoPost) Post(w http.ResponseWriter, r *http.Request) (int, interface{}) {
	return http.StatusNotImplemented, "POST is not supported"
}

// Objects implementing the Put interface response status NotImplemented(501).
type NoPut struct{}

func (NoPut) Put(w http.ResponseWriter, r *http.Request) (int, interface{}) {
	return http.StatusNotImplemented, "PUT is not supported"
}

// Objects implementing the Delete interface response status NotImplemented(501).
type NoDelete struct{}

func (NoDelete) Delete(w http.ResponseWriter, r *http.Request) (int, interface{}) {
	return http.StatusNotImplemented, "DELETE is not supported"
}

// Objects implementing the Patch interface response status NotImplemented(501).
type NoPatch struct{}

func (NoPatch) Patch(w http.ResponseWriter, r *http.Request) (int, interface{}) {
	return http.StatusNotImplemented, "PATCH is not supported"
}

// Objects implementing the Handler interface can be registered to serve a particular path or subtree in the HTTP server.
type Handler struct {
	mux          *http.ServeMux
	ErrorHandler func(error)
	PreHandler   func(r *http.Request) (int, error)
	PostHandler  func(r *http.Request, status int, data interface{})
}

// NewHandler returns a new Handler.
func NewHandler() (h *Handler) {
	h = &Handler{
		mux: http.NewServeMux(),
	}
	return
}

// Internal error handler
func (h *Handler) err(err error) {
	if h.ErrorHandler != nil {
		h.ErrorHandler(err)
	}
}

// Internal wrapping handler
func (h *Handler) wrap(f HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if h.PreHandler != nil {
			status, err := h.PreHandler(r)
			if err != nil {
				h.writeErr(w, Errorf(status, err.Error()))
				return
			}
		}
		status, data := f(w, r)
		if h.PostHandler != nil {
			h.PostHandler(r, status, data)
		}
		if err := h.writeJson(w, status, data); err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error()))
			h.err(err)
		}
	}
}

// AddResource adds a resource to a path. The resource must implement at least one of Get, Post, Put, Delete and Patch interface.
func (h *Handler) AddResource(pattern string, res interface{}) (err error) {
	switch res.(type) {
	case Get, Post, Put, Delete, Patch:
	default:
		return fmt.Errorf("`%T` is not a legal resource", res)
	}
	h.mux.Handle(pattern, h.wrap(h.rest(res)))
	return
}

// AddRPC adds a Remote Procedure Call to a path.
func (h *Handler) AddRPC(pattern string, f HandlerFunc) {
	h.mux.Handle(pattern, h.wrap(f))
}

// Internal wraper for AddResource.
func (h *Handler) rest(res interface{}) HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) (status int, data interface{}) {
		var hf HandlerFunc
		switch r.Method {
		case GET:
			if r, ok := res.(Get); ok {
				hf = r.Get
			} else {
				hf = (&NoGet{}).Get
			}
		case POST:
			if r, ok := res.(Post); ok {
				hf = r.Post
			} else {
				hf = (&NoPost{}).Post
			}
		case PUT:
			if r, ok := res.(Put); ok {
				hf = r.Put
			} else {
				hf = (&NoPut{}).Put
			}
		case DELETE:
			if r, ok := res.(Delete); ok {
				hf = r.Delete
			} else {
				hf = (&NoDelete{}).Delete
			}
		case PATCH:
			if r, ok := res.(Patch); ok {
				hf = r.Patch
			} else {
				hf = (&NoPatch{}).Patch
			}
		}
		return hf(w, r)
	}
}

// ServeHTTP calls HandlerFunc
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.ParseForm() != nil {
		h.writeErr(w, Errorf(http.StatusBadRequest, "Bad request for `%s`", r.URL.RequestURI()))
		return
	}
	handler, pattern := h.mux.Handler(r)
	if pattern == "" {
		h.writeErr(w, Errorf(http.StatusNotFound, "No handler for `%s`", r.URL.RequestURI()))
		return
	}
	handler.ServeHTTP(w, r)
}

// Internal responsing.
func (h *Handler) writeJson(w http.ResponseWriter, status int, data interface{}) error {
	content, err := json.Marshal(data)
	if err != nil {
		return err
	}
	w.WriteHeader(status)
	_, err = w.Write(content)
	return err
}

// Internal error responsing.
func (h *Handler) writeErr(w http.ResponseWriter, apierr apiErr) {
	if err := h.writeJson(w, apierr.status, apierr.message); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(err.Error()))
		h.err(err)
	}
}
<commit_msg>3xx is for redirecting<commit_after>// Possum is a micro web-api framework for Go.
package possum

import (
	"encoding/json"
	"fmt"
	"net/http"
)

const (
	GET    = "GET"
	POST   = "POST"
	PUT    = "PUT"
	DELETE = "DELETE"
	PATCH  = "PATCH"

	StatusNone = 0
)

// Processing function returning HTTP status code and response object witch will be marshaled to JSON.
type HandlerFunc func(w http.ResponseWriter, r *http.Request) (int, interface{})

type (
	// Interface for handling GET request.
	Get interface {
		Get(w http.ResponseWriter, r *http.Request) (int, interface{})
	}
	// Interface for handling PUT request.
	Put interface {
		Put(w http.ResponseWriter, r *http.Request) (int, interface{})
	}
	// Interface for handling POST request.
	Post interface {
		Post(w http.ResponseWriter, r *http.Request) (int, interface{})
	}
	// Interface for handling DELETE request.
	Delete interface {
		Delete(w http.ResponseWriter, r *http.Request) (int, interface{})
	}
	// Interface for handling PATCH request.
	Patch interface {
		Patch(w http.ResponseWriter, r *http.Request) (int, interface{})
	}
)

// Objects implementing the Get interface response status NotImplemented(501).
type NoGet struct{}

func (NoGet) Get(w http.ResponseWriter, r *http.Request) (int, interface{}) {
	return http.StatusNotImplemented, "GET is not supported"
}

// Objects implementing the Post interface response status NotImplemented(501).
type NoPost struct{}

func (NoPost) Post(w http.ResponseWriter, r *http.Request) (int, interface{}) {
	return http.StatusNotImplemented, "POST is not supported"
}

// Objects implementing the Put interface response status NotImplemented(501).
type NoPut struct{}

func (NoPut) Put(w http.ResponseWriter, r *http.Request) (int, interface{}) {
	return http.StatusNotImplemented, "PUT is not supported"
}

// Objects implementing the Delete interface response status NotImplemented(501).
type NoDelete struct{}

func (NoDelete) Delete(w http.ResponseWriter, r *http.Request) (int, interface{}) {
	return http.StatusNotImplemented, "DELETE is not supported"
}

// Objects implementing the Patch interface response status NotImplemented(501).
type NoPatch struct{}

func (NoPatch) Patch(w http.ResponseWriter, r *http.Request) (int, interface{}) {
	return http.StatusNotImplemented, "PATCH is not supported"
}

// Objects implementing the Handler interface can be registered to serve a particular path or subtree in the HTTP server.
type Handler struct {
	mux          *http.ServeMux
	ErrorHandler func(error)
	PreHandler   func(r *http.Request) (int, error)
	PostHandler  func(r *http.Request, status int, data interface{})
}

// NewHandler returns a new Handler.
func NewHandler() (h *Handler) {
	h = &Handler{
		mux: http.NewServeMux(),
	}
	return
}

// Internal error handler
func (h *Handler) err(err error) {
	if h.ErrorHandler != nil {
		h.ErrorHandler(err)
	}
}

// Internal wrapping handler
func (h *Handler) wrap(f HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if h.PreHandler != nil {
			status, err := h.PreHandler(r)
			if err != nil {
				h.writeErr(w, Errorf(status, err.Error()))
				return
			}
		}
		status, data := f(w, r)
		if h.PostHandler != nil {
			h.PostHandler(r, status, data)
		}
		switch {
			case status == StatusNone:
			case status >= 300 && status < 400:
				if urlStr, ok := data.(string); ok {
					http.Redirect(w, r, urlStr, status)
				}
			default:
			if err := h.writeJson(w, status, data); err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				h.err(err)
			}
		}
	}
}

// AddResource adds a resource to a path. The resource must implement at least one of Get, Post, Put, Delete and Patch interface.
func (h *Handler) AddResource(pattern string, res interface{}) (err error) {
	switch res.(type) {
	case Get, Post, Put, Delete, Patch:
	default:
		return fmt.Errorf("`%T` is not a legal resource", res)
	}
	h.mux.Handle(pattern, h.wrap(h.rest(res)))
	return
}

// AddRPC adds a Remote Procedure Call to a path.
func (h *Handler) AddRPC(pattern string, f HandlerFunc) {
	h.mux.Handle(pattern, h.wrap(f))
}

// Internal wraper for AddResource.
func (h *Handler) rest(res interface{}) HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) (status int, data interface{}) {
		var hf HandlerFunc
		switch r.Method {
		case GET:
			if r, ok := res.(Get); ok {
				hf = r.Get
			} else {
				hf = (&NoGet{}).Get
			}
		case POST:
			if r, ok := res.(Post); ok {
				hf = r.Post
			} else {
				hf = (&NoPost{}).Post
			}
		case PUT:
			if r, ok := res.(Put); ok {
				hf = r.Put
			} else {
				hf = (&NoPut{}).Put
			}
		case DELETE:
			if r, ok := res.(Delete); ok {
				hf = r.Delete
			} else {
				hf = (&NoDelete{}).Delete
			}
		case PATCH:
			if r, ok := res.(Patch); ok {
				hf = r.Patch
			} else {
				hf = (&NoPatch{}).Patch
			}
		}
		return hf(w, r)
	}
}

// ServeHTTP calls HandlerFunc
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.ParseForm() != nil {
		h.writeErr(w, Errorf(http.StatusBadRequest, "Bad request for `%s`", r.URL.RequestURI()))
		return
	}
	handler, pattern := h.mux.Handler(r)
	if pattern == "" {
		h.writeErr(w, Errorf(http.StatusNotFound, "No handler for `%s`", r.URL.RequestURI()))
		return
	}
	handler.ServeHTTP(w, r)
}

// Internal responsing.
func (h *Handler) writeJson(w http.ResponseWriter, status int, data interface{}) error {
	content, err := json.Marshal(data)
	if err != nil {
		return err
	}
	w.WriteHeader(status)
	_, err = w.Write(content)
	return err
}

// Internal error responsing.
func (h *Handler) writeErr(w http.ResponseWriter, apierr apiErr) {
	if err := h.writeJson(w, apierr.status, apierr.message); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(err.Error()))
		h.err(err)
	}
}
<|endoftext|>


<commit_before>package git

import (
	"sync"
	"unsafe"
)

type HandleList struct {
	sync.RWMutex
	// stores the Go pointers
	handles []interface{}
	// indicates which indices are in use
	set map[uintptr]bool
}

func NewHandleList() *HandleList {
	return &HandleList{
		handles: make([]interface{}, 5),
		set:     make(map[uintptr]bool),
	}
}

// findUnusedSlot finds the smallest-index empty space in our
// list. You must only run this function while holding a write lock.
func (v *HandleList) findUnusedSlot() uintptr {
	for i := 1; i < len(v.handles); i++ {
		isUsed := v.set[uintptr(i)]
		if !isUsed {
			return uintptr(i)
		}
	}

	// reaching here means we've run out of entries so append and
	// return the new index, which is equal to the old length.
	slot := len(v.handles)
	v.handles = append(v.handles, nil)

	return uintptr(slot)
}

// Track adds the given pointer to the list of pointers to track and
// returns a pointer value which can be passed to C as an opaque
// pointer.
func (v *HandleList) Track(pointer interface{}) unsafe.Pointer {
	v.Lock()

	slot := v.findUnusedSlot()
	v.handles[slot] = pointer
	v.set[slot] = true

	v.Unlock()

	return unsafe.Pointer(slot)
}

// Untrack stops tracking the pointer given by the handle
func (v *HandleList) Untrack(handle unsafe.Pointer) {
	slot := uintptr(handle)

	v.Lock()

	v.handles[slot] = nil
	delete(v.set, slot)

	v.Unlock()
}

// Get retrieves the pointer from the given handle
func (v *HandleList) Get(handle unsafe.Pointer) interface{} {
	slot := uintptr(handle)

	v.RLock()

	if _, ok := v.set[slot]; !ok {
		panic("invalid pointer handle")
	}

	ptr := v.handles[slot]

	v.RUnlock()

	return ptr
}
<commit_msg>handles: print pointer handle on panic.<commit_after>package git

import (
	"fmt"
	"sync"
	"unsafe"
)

type HandleList struct {
	sync.RWMutex
	// stores the Go pointers
	handles []interface{}
	// indicates which indices are in use
	set map[uintptr]bool
}

func NewHandleList() *HandleList {
	return &HandleList{
		handles: make([]interface{}, 5),
		set:     make(map[uintptr]bool),
	}
}

// findUnusedSlot finds the smallest-index empty space in our
// list. You must only run this function while holding a write lock.
func (v *HandleList) findUnusedSlot() uintptr {
	for i := 1; i < len(v.handles); i++ {
		isUsed := v.set[uintptr(i)]
		if !isUsed {
			return uintptr(i)
		}
	}

	// reaching here means we've run out of entries so append and
	// return the new index, which is equal to the old length.
	slot := len(v.handles)
	v.handles = append(v.handles, nil)

	return uintptr(slot)
}

// Track adds the given pointer to the list of pointers to track and
// returns a pointer value which can be passed to C as an opaque
// pointer.
func (v *HandleList) Track(pointer interface{}) unsafe.Pointer {
	v.Lock()

	slot := v.findUnusedSlot()
	v.handles[slot] = pointer
	v.set[slot] = true

	v.Unlock()

	return unsafe.Pointer(slot)
}

// Untrack stops tracking the pointer given by the handle
func (v *HandleList) Untrack(handle unsafe.Pointer) {
	slot := uintptr(handle)

	v.Lock()

	v.handles[slot] = nil
	delete(v.set, slot)

	v.Unlock()
}

// Get retrieves the pointer from the given handle
func (v *HandleList) Get(handle unsafe.Pointer) interface{} {
	slot := uintptr(handle)

	v.RLock()

	if _, ok := v.set[slot]; !ok {
		panic(fmt.Sprintf("invalid pointer handle: %p", handle))
	}

	ptr := v.handles[slot]

	v.RUnlock()

	return ptr
}
<|endoftext|>


<commit_before>package models

import (
  "github.com/spacedock-io/registry/db"
)

type Repo struct {
  Id            int64
  RegistryId    string `sql:"not null"`
  Namespace     string `sql:"not null"`
  Name          string `sql:"not null;unique"`
  Tokens        []Token
}

func GetRepo(namespace string, repo string) (*Repo, error) {
  r := &Repo{}
  q := db.DB.Where("namespace = ? and name = ?", namespace, repo).Find(r)

  if q.Error != nil {
    if q.RecordNotFound() {
      return nil, NotFoundErr
    } else { return nil, DBErr }
  }
  return r, nil
}

func (r *Repo) Create(repo, ns, regId string, uid int64) (string, error) {
  var fullname string
  r.Name = repo
  r.RegistryId = regId

  if len(ns) == 0 {
    fullname = "library/" + repo
    r.Namespace = ""
  } else {
    fullname = ns + "/" + repo
    r.Namespace = ns
  }

  // @TODO: make sure this access level is right
  t, ok := CreateToken("write", uid, fullname)
  if !ok { return "", TokenErr }

  r.Tokens = append(r.Tokens, t)

  q := db.DB.Save(r)
  if q.Error != nil {
    return "", DBErr
  }
  return t.String(), nil
}

func (repo *Repo) Delete() error {
  q := db.DB.Delete(repo)
  if q.Error != nil {
    return DBErr
  }
  return nil
}

func (repo *Repo) HasToken(token string) bool {
  for _, v := range repo.Tokens {
    if v.String() == token {
      return true
    }
  }

  return false
}
<commit_msg>Make repo.Create accept parsed image ids<commit_after>package models

import (
  "github.com/spacedock-io/registry/db"
)

type Repo struct {
  Id            int64
  RegistryId    string `sql:"not null"`
  Namespace     string `sql:"not null"`
  Name          string `sql:"not null;unique"`
  Tokens        []Token
  Images        []Image
}

func GetRepo(namespace string, repo string) (*Repo, error) {
  r := &Repo{}
  q := db.DB.Where("namespace = ? and name = ?", namespace, repo).Find(r)

  if q.Error != nil {
    if q.RecordNotFound() {
      return nil, NotFoundErr
    } else { return nil, DBErr }
  }
  return r, nil
}

func (r *Repo) Create(repo, ns, regId string, uid int64,
                      images []map[string]interface{}) (string, error) {
  var fullname string
  r.Name = repo
  r.RegistryId = regId

  if len(ns) == 0 {
    fullname = "library/" + repo
    r.Namespace = ""
  } else {
    fullname = ns + "/" + repo
    r.Namespace = ns
  }

  // @TODO: make sure this access level is right
  t, ok := CreateToken("write", uid, fullname)
  if !ok { return "", TokenErr }

  r.Tokens = append(r.Tokens, t)

  for _, v := range images {
    img := Image{}
    img.Create(v["id"].(string))
    r.Images = append(r.Images, img)
  }

  q := db.DB.Save(r)
  if q.Error != nil {
    return "", DBErr
  }
  return t.String(), nil
}

func (repo *Repo) Delete() error {
  q := db.DB.Delete(repo)
  if q.Error != nil {
    return DBErr
  }
  return nil
}

func (repo *Repo) HasToken(token string) bool {
  for _, v := range repo.Tokens {
    if v.String() == token {
      return true
    }
  }

  return false
}
<|endoftext|>


<commit_before>package models

import (
	"github.com/coopernurse/gorp"
	"crypto/md5"
	"encoding/hex"
	"strconv"
	"time"
)

desctype User struct {
	Id                 int64     `db:"user_id"`
	Name               string    `db:"user_name"`
	RealName           string    `db:"user_real_name"`
	Password           string    `db:"-"`
	HashedPassword     string    `db:"user_password"`
	NewPassword        string    `db:"user_newpassword"`
	NewPassTime        string    `db:"user_newpass_time"`
	Email              string    `db:"user_email"`
	Touched            string    `db:"user_touched"`
	Token              string    `db:"user_token"`
	EmailAuthenticated string    `db:"user_email_authenticated"`
	EmailToken         string    `db:"user_email_token"`
	EmailTokenExpires  string    `db:"user_email_token_expires"`
	Registration       string    `db:"user_registration"`
	EditCount          int64     `db:"user_editcount"`
	BirthDate          time.Time `db:"user_birthdate"`
	Options            []byte    `db:"user_options"`
}

func (user *User) ValidPassword(password string) bool {
	hasher := md5.New()
	hasher.Write([]byte(password))
	hash := hex.EncodeToString(hasher.Sum(nil))

	hash = strconv.FormatInt(user.Id, 10) + "-" + hash

	hasher.Reset()
	hasher.Write([]byte(hash))
	hash = hex.EncodeToString(hasher.Sum(nil))
	return user.HashedPassword == hash
}

func (u *User) FindByName(dbmap *gorp.DbMap) bool {
	err := dbmap.SelectOne(&u, "select * from user where user_name=?", u.Name)
	if err != nil {
		return false
	}
	return true
}<commit_msg>[PLATFORM-555] Support for NULL handeling in user model<commit_after>package models

import (
	"github.com/coopernurse/gorp"
	"crypto/md5"
	"encoding/hex"
	"strconv"
	"time"
)

desctype User struct {
	Id                 int64      `db:"user_id"`
	Name               string     `db:"user_name"`
	RealName           string     `db:"user_real_name"`
	Password           string     `db:"-"`
	HashedPassword     string     `db:"user_password"`
	NewPassword        string     `db:"user_newpassword"`
	NewPassTime        *string    `db:"user_newpass_time"`
	Email              string     `db:"user_email"`
	Touched            string     `db:"user_touched"`
	Token              string     `db:"user_token"`
	EmailAuthenticated *string    `db:"user_email_authenticated"`
	EmailToken         *string    `db:"user_email_token"`
	EmailTokenExpires  *string    `db:"user_email_token_expires"`
	Registration       *string    `db:"user_registration"`
	EditCount          *int64     `db:"user_editcount"`
	BirthDate          *time.Time `db:"user_birthdate"`
	Options            []byte     `db:"user_options"`
}

func (user *User) ValidPassword(password string) bool {
	hasher := md5.New()
	hasher.Write([]byte(password))
	hash := hex.EncodeToString(hasher.Sum(nil))

	hash = strconv.FormatInt(user.Id, 10) + "-" + hash

	hasher.Reset()
	hasher.Write([]byte(hash))
	hash = hex.EncodeToString(hasher.Sum(nil))
	return user.HashedPassword == hash
}

func (u *User) FindByName(dbmap *gorp.DbMap) bool {
	err := dbmap.SelectOne(&u, "select * from user where user_name=?", u.Name)
	if err != nil {
		return false
	}
	return true
}<|endoftext|>


<commit_before>package json

import (
	"strings"
	"path/filepath"
	"github.com/spf13/viper"
	"fmt"
	"os"
	"github.com/joho/godotenv"
	"log"
	"github.com/ethereal-go/ethereal/root/config"
)
const (
	FileName = "app.json"
	DirConf  = "config"
)

type ConfigurationJson struct {
	BasePath          []string
	FileName          string
	ExtensionFileName string
}

func NewConfig() config.Configurable {
	return &ConfigurationJson{}
}

// Load configuration data set in application
func (c *ConfigurationJson) Load() {
	var err error
	s := strings.Split(FileName, ".")
	c.FileName, c.ExtensionFileName = s[0], s[1]

	workPath := BasePathClient()
	c.BasePath = append(c.BasePath, filepath.Join(workPath, DirConf), workPath)

	viper.SetConfigName(c.FileName)
	c.addAllPathsConfig(c.BasePath)

	err = viper.ReadInConfig() // Find and read the config file

	if err != nil { // Handle errors reading the config file
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
	err = godotenv.Load()
	if err != nil {
		log.Fatal("Error loading .env file")
	}
}

/**
/ Set all paths possible in application
*/
func (c ConfigurationJson) addAllPathsConfig(paths []string) {
	for _, path := range paths {
		viper.AddConfigPath(path)
	}
}

func BasePathClient() string {
	workPath, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	return workPath
}

<commit_msg>change text error config not found file<commit_after>package json

import (
	"strings"
	"path/filepath"
	"github.com/spf13/viper"
	"fmt"
	"os"
	"github.com/joho/godotenv"
	"log"
	"github.com/ethereal-go/ethereal/root/config"
)
const (
	FileName = "app.json"
	DirConf  = "config"
)

type ConfigurationJson struct {
	BasePath          []string
	FileName          string
	ExtensionFileName string
}

func NewConfig() config.Configurable {
	return &ConfigurationJson{}
}

// Load configuration data set in application
func (c *ConfigurationJson) Load() {
	var err error
	s := strings.Split(FileName, ".")
	c.FileName, c.ExtensionFileName = s[0], s[1]

	workPath := BasePathClient()
	c.BasePath = append(c.BasePath, filepath.Join(workPath, DirConf), workPath)

	viper.SetConfigName(c.FileName)
	c.addAllPathsConfig(c.BasePath)

	err = viper.ReadInConfig() // Find and read the config file

	if err != nil { // Handle errors reading the config file
		panic(fmt.Errorf("%s \n", err))
	}
	err = godotenv.Load()
	if err != nil {
		log.Fatal("Error loading .env file")
	}
}

/**
/ Set all paths possible in application
*/
func (c ConfigurationJson) addAllPathsConfig(paths []string) {
	for _, path := range paths {
		viper.AddConfigPath(path)
	}
}

func BasePathClient() string {
	workPath, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	return workPath
}

<|endoftext|>


<commit_before>package monit

import (
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"
)

type MonitFile struct {
	Checks []Check
}

type Check interface{}

type ProcessCheck struct {
	Name         string
	Pidfile      string
	StartProgram string
	StopProgram  string
	FailedSocket FailedSocket
	FailedHost   FailedHost
	Group        string
	DependsOn    string
}

type FileCheck struct {
	Name         string
	Path         string
	IfChanged    string
	FailedSocket FailedSocket
	FailedHost   FailedHost
	Group        string
	DependsOn    string
}

type FailedSocket struct {
	SocketFile string
	Timeout    int
	NumCycles  int
	Action     string
}

type FailedHost struct {
	Host      string
	Port      string
	Protocol  string
	Timeout   int
	NumCycles int
	Action    string
}

func ReadMonitFile(filepath string) (MonitFile, error) {
	bytes, err := ioutil.ReadFile(filepath)

	if err != nil {
		// Do something
	}

	lines := strings.Split(string(bytes), "\n")

	checks := []Check{}

	i := 0
	for _, line := range lines {
		processMatch, err := regexp.Match("check process", []byte(line))
		fileMatch, err := regexp.Match("check file", []byte(line))

		if err != nil {
			// Do something
		}

		if processMatch {
			check := createProcessCheck(lines, i)
			checks = append(checks, check)
		} else if fileMatch {
			check := createFileCheck(lines, i)
			checks = append(checks, check)
		}

		i++
	}

	monitFile := MonitFile{checks}

	return monitFile, nil
}

func createProcessCheck(lines []string, startingIndex int) ProcessCheck {
	name := captureWithRegex(lines, `check process ([\w"\.]+)`, true)
	pidfile := captureWithRegex(lines, `with pidfile ([\w"/\.]+)`, true)
	startProgram := captureWithRegex(lines, `start program (.*)$`, true)
	stopProgram := captureWithRegex(lines, `stop program (.*)$`, true)
	group := captureWithRegex(lines, `group (\w+)`, true)
	dependsOn := captureWithRegex(lines, `depends on (\w+)`, true)
	failedSocket := parseFailedUnixSocket(lines)
	failedHost := parseFailedHost(lines)

	check := ProcessCheck{
		Name:         name,
		Pidfile:      pidfile,
		StartProgram: startProgram,
		StopProgram:  stopProgram,
		FailedSocket: failedSocket,
		FailedHost:   failedHost,
		Group:        group,
		DependsOn:    dependsOn,
	}

	return check
}

func createFileCheck(lines []string, startingIndex int) FileCheck {
	name := captureWithRegex(lines, `check file ([\w"\.]+)`, true)
	failedHost := parseFailedHost(lines)
	failedSocket := parseFailedUnixSocket(lines)

	path := captureWithRegex(lines, `with path ([\w"/\.]+)`, true)
	ifChanged := captureWithRegex(lines, `if changed (.*)$`, true)
	group := captureWithRegex(lines, `group (\w+)`, true)
	dependsOn := captureWithRegex(lines, `depends on (\w+)`, true)

	check := FileCheck{
		Name:         name,
		Path:         path,
		IfChanged:    ifChanged,
		FailedSocket: failedSocket,
		FailedHost:   failedHost,
		Group:        group,
		DependsOn:    dependsOn,
	}

	return check
}

func parseFailedUnixSocket(lines []string) FailedSocket {
	var startingIndex, endingIndex int
	var socketFile, timeout, numCycles, action string
	var newLines []string

	for i, line := range lines {
		newProcessCheck, err := regexp.Match("check process", []byte(line))
		if err != nil {
			// Do something
		}

		newFileCheck, err := regexp.Match("check file", []byte(line))
		if err != nil {
			// Do something
		}

		if newProcessCheck || newFileCheck {
			break
		}

		socketMatch, err := regexp.Match("if failed unixsocket", []byte(line))

		if err != nil {
			// Do something
		}

		if socketMatch {
			startingIndex = i

			newLines = append([]string{}, lines[i:]...)
			socketFile = captureWithRegex(newLines, `if failed unixsocket (["/\w\.]+)`, false)
			timeout = captureWithRegex(newLines, `with timeout ([0-9]+) seconds`, false)
			numCycles = captureWithRegex(newLines, `for ([0-9]+) cycles`, false)
			action = captureWithRegex(newLines, `then ([a-z]+)`, false)

			for j, newLine := range newLines {
				thenMatch, err := regexp.Match("then ", []byte(newLine))

				if err != nil {
					// Do something
				}

				if thenMatch {
					endingIndex = i + j
				}
			}
		}
	}

	timeoutInt, err := strconv.Atoi(timeout)
	if err != nil {
		// Do something
	}

	numCyclesInt, err := strconv.Atoi(numCycles)
	if err != nil {
		// Do something
	}

	if endingIndex != 0 {
		removeElementsFromSlice(lines, startingIndex, endingIndex)
	}

	return FailedSocket{
		SocketFile: socketFile,
		Timeout:    timeoutInt,
		NumCycles:  numCyclesInt,
		Action:     action,
	}
}

func parseFailedHost(lines []string) FailedHost {
	var startingIndex, endingIndex int
	var host, port, protocol string
	var timeout, numCycles, action string
	var newLines []string

	for i, line := range lines {
		newProcessCheck, err := regexp.Match("check process", []byte(line))
		if err != nil {
			// Do something
		}

		newFileCheck, err := regexp.Match("check file", []byte(line))
		if err != nil {
			// Do something
		}

		if newProcessCheck || newFileCheck {
			break
		}

		hostMatch, err := regexp.Match("if failed", []byte(line))

		if err != nil {
			// Do something
		}

		if hostMatch {
			startingIndex = i

			newLines = append([]string{}, lines[i:]...)
			host = captureWithRegex(newLines, `if failed host ([\w\.]+)`, false)
			port = captureWithRegex(newLines, `port ([\d]+)`, false)
			protocol = captureWithRegex(newLines, `protocol ([\w]+)`, false)
			timeout = captureWithRegex(newLines, `with timeout ([0-9]+) seconds`, false)
			numCycles = captureWithRegex(newLines, `for ([0-9]+) cycles`, false)
			action = captureWithRegex(newLines, `then ([a-z]+)`, false)

			for j, newLine := range newLines {
				thenMatch, err := regexp.Match("then ", []byte(newLine))

				if err != nil {
					// Do something
				}

				if thenMatch {
					endingIndex = i + j
				}
			}
		}
	}

	timeoutInt, err := strconv.Atoi(timeout)
	if err != nil {
		// Do something
	}

	numCyclesInt, err := strconv.Atoi(numCycles)
	if err != nil {
		// Do something
	}

	if endingIndex != 0 {
		removeElementsFromSlice(lines, startingIndex, endingIndex)
	}

	return FailedHost{
		Host:      host,
		Port:      port,
		Protocol:  protocol,
		Timeout:   timeoutInt,
		NumCycles: numCyclesInt,
		Action:    action,
	}
}

func captureWithRegex(lines []string, reg string, removeLine bool) string {
	var myString string

	for i, line := range lines {
		regex := regexp.MustCompile(reg)
		values := regex.FindStringSubmatch(line)

		newProcessCheck, err := regexp.Match("check process", []byte(line))
		if err != nil {
			// Do something
		}

		newFileCheck, err := regexp.Match("check file", []byte(line))
		if err != nil {
			// Do something
		}

		if len(values) > 1 {
			myString = strings.TrimSpace(values[1])

			if removeLine {
				lines = removeElementsFromSlice(lines, i, len(lines)-1)
			}

			break
		} else if newProcessCheck || newFileCheck {
			break
		}
	}

	stripReg := regexp.MustCompile(`"([^"]*)"`)
	return stripReg.ReplaceAllString(myString, "${1}")
}

func removeElementsFromSlice(slice []string, startingIndex int, endingIndex int) []string {
	return append(slice[:startingIndex], slice[endingIndex:]...)
}
<commit_msg>Refactor failed unixsocket and failed host parsing logic<commit_after>package monit

import (
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"
)

type MonitFile struct {
	Checks []Check
}

type Check interface{}

type ProcessCheck struct {
	Name         string
	Pidfile      string
	StartProgram string
	StopProgram  string
	FailedSocket FailedSocket
	FailedHost   FailedHost
	Group        string
	DependsOn    string
}

type FileCheck struct {
	Name         string
	Path         string
	IfChanged    string
	FailedSocket FailedSocket
	FailedHost   FailedHost
	Group        string
	DependsOn    string
}

type FailedSocket struct {
	SocketFile string
	Timeout    int
	NumCycles  int
	Action     string
}

type FailedHost struct {
	Host      string
	Port      string
	Protocol  string
	Timeout   int
	NumCycles int
	Action    string
}

func ReadMonitFile(filepath string) (MonitFile, error) {
	bytes, err := ioutil.ReadFile(filepath)

	if err != nil {
		// Do something
	}

	lines := strings.Split(string(bytes), "\n")

	checks := []Check{}

	i := 0
	for _, line := range lines {
		processMatch, err := regexp.Match("check process", []byte(line))
		fileMatch, err := regexp.Match("check file", []byte(line))

		if err != nil {
			// Do something
		}

		if processMatch {
			check := createProcessCheck(lines, i)
			checks = append(checks, check)
		} else if fileMatch {
			check := createFileCheck(lines, i)
			checks = append(checks, check)
		}

		i++
	}

	monitFile := MonitFile{checks}

	return monitFile, nil
}

func createProcessCheck(lines []string, startingIndex int) ProcessCheck {
	name := captureWithRegex(lines, `check process ([\w"\.]+)`, true)
	pidfile := captureWithRegex(lines, `with pidfile ([\w"/\.]+)`, true)
	startProgram := captureWithRegex(lines, `start program (.*)$`, true)
	stopProgram := captureWithRegex(lines, `stop program (.*)$`, true)
	group := captureWithRegex(lines, `group (\w+)`, true)
	dependsOn := captureWithRegex(lines, `depends on (\w+)`, true)
	failedSocket := parseFailedUnixSocket(lines)
	failedHost := parseFailedHost(lines)

	check := ProcessCheck{
		Name:         name,
		Pidfile:      pidfile,
		StartProgram: startProgram,
		StopProgram:  stopProgram,
		FailedSocket: failedSocket,
		FailedHost:   failedHost,
		Group:        group,
		DependsOn:    dependsOn,
	}

	return check
}

func createFileCheck(lines []string, startingIndex int) FileCheck {
	name := captureWithRegex(lines, `check file ([\w"\.]+)`, true)
	failedHost := parseFailedHost(lines)
	failedSocket := parseFailedUnixSocket(lines)

	path := captureWithRegex(lines, `with path ([\w"/\.]+)`, true)
	ifChanged := captureWithRegex(lines, `if changed (.*)$`, true)
	group := captureWithRegex(lines, `group (\w+)`, true)
	dependsOn := captureWithRegex(lines, `depends on (\w+)`, true)

	check := FileCheck{
		Name:         name,
		Path:         path,
		IfChanged:    ifChanged,
		FailedSocket: failedSocket,
		FailedHost:   failedHost,
		Group:        group,
		DependsOn:    dependsOn,
	}

	return check
}

func parseFailedUnixSocket(lines []string) FailedSocket {
	values := parseGroupBlock(
		lines,
		"socketFile",
		map[string]string{
			"socketFile": `if failed unixsocket (["/\w\.]+)`,
			"timeout":    `with timeout ([0-9]+) seconds`,
			"numCycles":  `for ([0-9]+) cycles`,
			"action":     `then ([a-z]+)`,
		},
	)

	socketFile := values["socketFile"]
	timeout := values["timeout"]
	numCycles := values["numCycles"]
	action := values["action"]

	timeoutInt, err := strconv.Atoi(timeout)
	if err != nil {
		// Do something
	}

	numCyclesInt, err := strconv.Atoi(numCycles)
	if err != nil {
		// Do something
	}

	return FailedSocket{
		SocketFile: socketFile,
		Timeout:    timeoutInt,
		NumCycles:  numCyclesInt,
		Action:     action,
	}
}

func parseFailedHost(lines []string) FailedHost {
	values := parseGroupBlock(
		lines,
		"host",
		map[string]string{
			"host":      `if failed host ([\w\.]+)`,
			"port":      `port ([\d]+)`,
			"protocol":  `protocol ([\w]+)`,
			"timeout":   `with timeout ([0-9]+) seconds`,
			"numCycles": `for ([0-9]+) cycles`,
			"action":    `then ([a-z]+)`,
		},
	)

	host := values["host"]
	port := values["port"]
	protocol := values["protocol"]
	timeout := values["timeout"]
	numCycles := values["numCycles"]
	action := values["action"]

	timeoutInt, err := strconv.Atoi(timeout)
	if err != nil {
		// Do something
	}

	numCyclesInt, err := strconv.Atoi(numCycles)
	if err != nil {
		// Do something
	}

	return FailedHost{
		Host:      host,
		Port:      port,
		Protocol:  protocol,
		Timeout:   timeoutInt,
		NumCycles: numCyclesInt,
		Action:    action,
	}
}

func parseGroupBlock(lines []string, keyRegex string, regexes map[string]string) map[string]string {
	var startingIndex, endingIndex int
	var newLines []string
	values := map[string]string{}

	startingRegex := regexp.MustCompile(regexes[keyRegex])

	for i, line := range lines {
		newProcessCheck, err := regexp.Match("check process", []byte(line))
		if err != nil {
			// Do something
		}

		newFileCheck, err := regexp.Match("check file", []byte(line))
		if err != nil {
			// Do something
		}

		if newProcessCheck || newFileCheck {
			break
		}

		match := startingRegex.Match([]byte(line))

		if match {
			startingIndex = i

			newLines = append([]string{}, lines[i:]...)

			for key, regex := range regexes {
				values[key] = captureWithRegex(newLines, regex, false)
			}

			for j, newLine := range newLines {
				thenMatch, err := regexp.Match("then ", []byte(newLine))

				if err != nil {
					// Do something
				}

				if thenMatch {
					endingIndex = i + j
				}
			}
		}
	}

	if endingIndex != 0 {
		removeElementsFromSlice(lines, startingIndex, endingIndex)
	}

	return values
}

func captureWithRegex(lines []string, reg string, removeLine bool) string {
	var myString string

	for i, line := range lines {
		regex := regexp.MustCompile(reg)
		values := regex.FindStringSubmatch(line)

		newProcessCheck, err := regexp.Match("check process", []byte(line))
		if err != nil {
			// Do something
		}

		newFileCheck, err := regexp.Match("check file", []byte(line))
		if err != nil {
			// Do something
		}

		if len(values) > 1 {
			myString = strings.TrimSpace(values[1])

			if removeLine {
				lines = removeElementsFromSlice(lines, i, len(lines)-1)
			}

			break
		} else if newProcessCheck || newFileCheck {
			break
		}
	}

	stripReg := regexp.MustCompile(`"([^"]*)"`)
	return stripReg.ReplaceAllString(myString, "${1}")
}

func removeElementsFromSlice(slice []string, startingIndex int, endingIndex int) []string {
	return append(slice[:startingIndex], slice[endingIndex:]...)
}
<|endoftext|>