Skip to content

Commit

Permalink
Code cleanup
Browse files Browse the repository at this point in the history
- Removed Http prefix from all types.
- Moved HttpHeader build-related functions to Header Builder type.
- Created a JSONErrorBuilder for JSONError building.
- Improved Travis-CI to include Go v1.4, v1.5 and latest.
- Improved Travis-CI to lint and vet.
- Migrated to Coveralls.
  • Loading branch information
skarllot committed Jan 2, 2016
1 parent 48ccd1e commit f23fcd1
Show file tree
Hide file tree
Showing 14 changed files with 393 additions and 195 deletions.
17 changes: 17 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
language: go

go:
- 1.4
- 1.5
- tip

before_script:
- go get -u github.com/golang/lint/golint
- go get -u github.com/axw/gocov/gocov
- go get -u github.com/mattn/goveralls
- if ! go get github.com/golang/tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi

script:
- go test -v --race ./...
- goveralls -service=travis-ci -repotoken $COVERALLS_TOKEN

after_script:
- test -z "$(gofmt -s -l -w . | tee /dev/stderr)"
- test -z "$(golint ./... | tee /dev/stderr)"
- go vet ./...
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ a toolset to help HTTP server implementation.

## Status

[![Build Status](https://travis-ci.org/raiqub/http.svg?branch=master)](https://travis-ci.org/raiqub/http) [![Coverage](http://gocover.io/_badge/github.com/raiqub/http)](http://gocover.io/github.com/raiqub/http) [![GoDoc](https://godoc.org/github.com/raiqub/http?status.svg)](http://godoc.org/github.com/raiqub/http)
[![Build Status](https://travis-ci.org/raiqub/http.svg?branch=master)](https://travis-ci.org/raiqub/http)
[![Coverage Status](https://coveralls.io/repos/raiqub/http/badge.svg?branch=master&service=github)](https://coveralls.io/github/raiqub/http?branch=master)
[![GoDoc](https://godoc.org/github.com/raiqub/http?status.svg)](http://godoc.org/github.com/raiqub/http)

## Installation

Expand Down
16 changes: 7 additions & 9 deletions auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,19 @@ package http

import "net/http"

// A HttpAuthenticable defines rules for a type that offers HTTP authentication.
type HttpAuthenticable interface {
// A Authenticable defines rules for a type that offers HTTP authentication.
type Authenticable interface {
TryAuthentication(r *http.Request, user, secret string) bool
}

// A HttpAuthenticator defines rules for a type that handles HTTP
// authentication.
type HttpAuthenticator interface {
// A Authenticator defines rules for a type that handles HTTP authentication.
type Authenticator interface {
AuthHandler(http.Handler) http.Handler
}

// HttpHeader_WwwAuthenticate creates a HTTP header to require client
// authentication.
func HttpHeader_WwwAuthenticate() *HttpHeader {
return &HttpHeader{
// WwwAuthenticate creates a HTTP header to require client authentication.
func (HeaderBuilder) WwwAuthenticate() *Header {
return &Header{
"WWW-Authenticate",
"", // type and params
}
Expand Down
31 changes: 17 additions & 14 deletions authbasic.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,33 @@ import (
)

const (
BASIC_PREFIX = "Basic "
BASIC_REALM = BASIC_PREFIX + "realm=\"Restricted\""
basicPrefix = "Basic "
basicRealm = basicPrefix + "realm=\"Restricted\""
)

// A HttpBasicAuthenticator represents a handler for HTTP basic authentication.
type HttpBasicAuthenticator struct {
HttpAuthenticable
// A BasicAuthenticator represents a handler for HTTP basic authentication.
type BasicAuthenticator struct {
Authenticable
}

// AuthHandler is a HTTP request middleware that enforces authentication.
func (self HttpBasicAuthenticator) AuthHandler(next http.Handler) http.Handler {
if self.HttpAuthenticable == nil {
func (auth BasicAuthenticator) AuthHandler(next http.Handler) http.Handler {
if auth.Authenticable == nil {
panic("HttpAuthenticable cannot be nil")
}

f := func(w http.ResponseWriter, r *http.Request) {
user, secret := ParseAuthHeader(r.Header.Get("Authorization"))
user, secret := parseAuthHeader(r.Header.Get("Authorization"))
if len(user) > 0 &&
len(secret) > 0 &&
self.TryAuthentication(r, user, secret) {
auth.TryAuthentication(r, user, secret) {
next.ServeHTTP(w, r)
return
}

HttpHeader_WwwAuthenticate().
SetValue(BASIC_REALM).
NewHeader().
WwwAuthenticate().
SetValue(basicRealm).
SetWriter(w.Header())
http.Error(w, http.StatusText(http.StatusUnauthorized),
http.StatusUnauthorized)
Expand All @@ -58,13 +59,13 @@ func (self HttpBasicAuthenticator) AuthHandler(next http.Handler) http.Handler {
return http.HandlerFunc(f)
}

func ParseAuthHeader(
func parseAuthHeader(
header string,
) (user, secret string) {
if !strings.HasPrefix(header, BASIC_PREFIX) {
if !strings.HasPrefix(header, basicPrefix) {
return
}
payload, err := base64.StdEncoding.DecodeString(header[len(BASIC_PREFIX):])
payload, err := base64.StdEncoding.DecodeString(header[len(basicPrefix):])
if err != nil {
return
}
Expand All @@ -77,3 +78,5 @@ func ParseAuthHeader(
user, secret = strings.TrimSpace(user), strings.TrimSpace(secret)
return
}

var _ Authenticator = (*BasicAuthenticator)(nil)
6 changes: 3 additions & 3 deletions chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ import (
"net/http"
)

// A HttpMiddlewareFunc represents a HTTP handler that is called before target
// A MiddlewareFunc represents a HTTP handler that is called before target
// HTTP handler.
type HttpMiddlewareFunc func(http.Handler) http.Handler
type MiddlewareFunc func(http.Handler) http.Handler

// A Chain represents a chain of HTTP middlewares that are called before target
// HTTP handler.
type Chain []HttpMiddlewareFunc
type Chain []MiddlewareFunc

// Get returns a HTTP handler which is a chain of middlewares and then the
// specified handler.
Expand Down
33 changes: 33 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2016 Fabrício Godoy <skarllot@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

package http

import (
"fmt"
)

// A InvalidTokenError represents an error when an invalid or expired token is
// requested.
type InvalidTokenError string

// Error returns string representation of current instance error.
func (e InvalidTokenError) Error() string {
return fmt.Sprintf(
"The requested token '%s' is invalid or is expired", string(e))
}
14 changes: 7 additions & 7 deletions httpheader.go → header.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,41 +20,41 @@ import (
"net/http"
)

// A HttpHeader represents a key-value pair in a HTTP header.
type HttpHeader struct {
// A Header represents a key-value pair in a HTTP header.
type Header struct {
// HTTP header field name.
Name string
// HTTP header field value.
Value string
}

// Clone make a copy of current instance.
func (s HttpHeader) Clone() *HttpHeader {
func (s Header) Clone() *Header {
return &s
}

// GetReader gets HTTP header value, as defined by current instance, from
// Request Header and sets to current instance.
func (s *HttpHeader) GetReader(h http.Header) *HttpHeader {
func (s *Header) GetReader(h http.Header) *Header {
s.Value = h.Get(s.Name)
return s
}

// SetName sets header name of current instance.
func (s *HttpHeader) SetName(name string) *HttpHeader {
func (s *Header) SetName(name string) *Header {
s.Name = name
return s
}

// SetValue sets header value of current instance.
func (s *HttpHeader) SetValue(value string) *HttpHeader {
func (s *Header) SetValue(value string) *Header {
s.Value = value
return s
}

// SetWriter sets HTTP header, as defined by current instance, to ResponseWriter
// Header.
func (s *HttpHeader) SetWriter(h http.Header) *HttpHeader {
func (s *Header) SetWriter(h http.Header) *Header {
h.Set(s.Name, s.Value)
return s
}
156 changes: 156 additions & 0 deletions headerbuilder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* Copyright 2015 Fabrício Godoy
*
* 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.
*/

package http

// A HeaderBuilder provides pre-defined HTTP headers.
type HeaderBuilder int

// NewHeader creates a new instance of HeaderBuilder.
func NewHeader() HeaderBuilder {
return HeaderBuilder(0)
}

// AccessControlAllowCredentials creates a HTTP header to CORS-able API indicate
// that authentication is allowed.
func (HeaderBuilder) AccessControlAllowCredentials() *Header {
return &Header{
"Access-Control-Allow-Credentials",
"", // boolean
}
}

// AccessControlAllowHeaders creates a HTTP header to CORS-able API indicate
// which HTTP headers are allowed.
func (HeaderBuilder) AccessControlAllowHeaders() *Header {
return &Header{
"Access-Control-Allow-Headers",
"", // comma-separated list
}
}

// AccessControlAllowMethods creates a HTTP header to CORS-able API indicate
// which HTTP methods are allowed to current resource.
func (HeaderBuilder) AccessControlAllowMethods() *Header {
return &Header{
"Access-Control-Allow-Methods",
"", // comma-separated list of HTTP methods
}
}

// AccessControlAllowOrigin creates a HTTP header to CORS-able API indicate
// which origin is expected.
func (HeaderBuilder) AccessControlAllowOrigin() *Header {
return &Header{
"Access-Control-Allow-Origin",
"", // http-formatted domain or asterisk to any
}
}

// AccessControlMaxAge creates a HTTP header to CORS-able API indicate how long
// preflight results should be cached.
func (HeaderBuilder) AccessControlMaxAge() *Header {
return &Header{
"Access-Control-Max-Age",
"", // seconds
}
}

// AccessControlRequestHeaders creates a HTTP header to CORS-able client
// indicate which headers will be used for request.
func (HeaderBuilder) AccessControlRequestHeaders() *Header {
return &Header{
"Access-Control-Request-Headers",
"", // comma-separated list of HTTP headers
}
}

// AccessControlRequestMethod creates a HTTP header to CORS-able client indicate
// which HTTP method will be used for request.
func (HeaderBuilder) AccessControlRequestMethod() *Header {
return &Header{
"Access-Control-Request-Method",
"", // HTTP method name
}
}

// ContentType creates a HTTP header builder to define a content type.
func (HeaderBuilder) ContentType() HeaderContentTypeBuilder {
return HeaderContentTypeBuilder(0)
}

// Empty creates a empty HTTP header.
func (HeaderBuilder) Empty() *Header {
return &Header{
"",
"",
}
}

// Location creates a HTTP header to define location of new object.
func (HeaderBuilder) Location() *Header {
return &Header{
"Location",
"", // relative http location
}
}

// Origin creates a HTTP header to CORS-able client indicate its address.
func (HeaderBuilder) Origin() *Header {
return &Header{
"Origin",
"", // http-formatted domain
}
}

// A HeaderContentTypeBuilder provides pre-defined Content Types HTTP headers.
type HeaderContentTypeBuilder int

// Empty creates a HTTP header to undefined content type.
func (HeaderContentTypeBuilder) Empty() *Header {
return &Header{
"Content-Type",
"",
}
}

// HTML creates a HTTP header to define HTML content type.
func (HeaderContentTypeBuilder) HTML() *Header {
return HeaderContentTypeBuilder(0).
Empty().
SetValue("text/html; charset=utf-8")
}

// JSON creates a HTTP header to define JSON content type.
func (HeaderContentTypeBuilder) JSON() *Header {
return HeaderContentTypeBuilder(0).
Empty().
SetValue("application/json; charset=utf-8")
}

// Text creates a HTTP header to define plain text content type.
func (HeaderContentTypeBuilder) Text() *Header {
return HeaderContentTypeBuilder(0).
Empty().
SetValue("text/plain; charset=utf-8")
}

// XML creates a HTTP header to define XML content type.
func (HeaderContentTypeBuilder) XML() *Header {
return HeaderContentTypeBuilder(0).
Empty().
SetValue("application/xml; charset=utf-8")
}
Loading

0 comments on commit f23fcd1

Please sign in to comment.