use pointer to AcmeURL everywhere

This has the benefit of not requiring us to copy very fat url.URL
objects when we pass them to funcs or call their methods.
This commit is contained in:
Jeff Hodges 2015-08-05 18:22:34 -07:00
parent 0957227ac3
commit 0f03494d56
13 changed files with 103 additions and 84 deletions

View File

@ -42,7 +42,7 @@ type mailer struct {
limit int
}
func (m *mailer) sendNags(parsedCert *x509.Certificate, contacts []core.AcmeURL) error {
func (m *mailer) sendNags(parsedCert *x509.Certificate, contacts []*core.AcmeURL) error {
expiresIn := int(parsedCert.NotAfter.Sub(time.Now()).Hours()/24) + 1
emails := []string{}
for _, contact := range contacts {

View File

@ -14,7 +14,6 @@ import (
"encoding/json"
"fmt"
"math/big"
"net/url"
"testing"
"text/template"
"time"
@ -89,23 +88,23 @@ func TestSendNags(t *testing.T) {
DNSNames: []string{"example.com"},
}
email, _ := url.Parse("mailto:rolandshoemaker@gmail.com")
emailB, _ := url.Parse("mailto:test@gmail.com")
email, _ := core.ParseAcmeURL("mailto:rolandshoemaker@gmail.com")
emailB, _ := core.ParseAcmeURL("mailto:test@gmail.com")
err = m.sendNags(cert, []core.AcmeURL{core.AcmeURL(*email)})
err = m.sendNags(cert, []*core.AcmeURL{email})
test.AssertNotError(t, err, "Failed to send warning messages")
test.AssertEquals(t, len(mc.Messages), 1)
test.AssertEquals(t, fmt.Sprintf(`hi, cert for DNS names example.com is going to expire in 2 days (%s)`, cert.NotAfter), mc.Messages[0])
mc.Clear()
err = m.sendNags(cert, []core.AcmeURL{core.AcmeURL(*email), core.AcmeURL(*emailB)})
err = m.sendNags(cert, []*core.AcmeURL{email, emailB})
test.AssertNotError(t, err, "Failed to send warning messages")
test.AssertEquals(t, len(mc.Messages), 2)
test.AssertEquals(t, fmt.Sprintf(`hi, cert for DNS names example.com is going to expire in 2 days (%s)`, cert.NotAfter), mc.Messages[0])
test.AssertEquals(t, fmt.Sprintf(`hi, cert for DNS names example.com is going to expire in 2 days (%s)`, cert.NotAfter), mc.Messages[1])
mc.Clear()
err = m.sendNags(cert, []core.AcmeURL{})
err = m.sendNags(cert, []*core.AcmeURL{})
test.AssertNotError(t, err, "Not an error to pass no email contacts")
test.AssertEquals(t, len(mc.Messages), 0)
}
@ -147,8 +146,8 @@ func TestFindExpiringCertificates(t *testing.T) {
test.AssertEquals(t, len(log.GetAllMatching("Searching for certificates that expire between.*")), 3)
// Add some expiring certificates and registrations
emailA, _ := url.Parse("mailto:one@mail.com")
emailB, _ := url.Parse("mailto:twp@mail.com")
emailA, _ := core.ParseAcmeURL("mailto:one@mail.com")
emailB, _ := core.ParseAcmeURL("mailto:twp@mail.com")
var keyA jose.JsonWebKey
var keyB jose.JsonWebKey
err = json.Unmarshal(jsonKeyA, &keyA)
@ -157,15 +156,15 @@ func TestFindExpiringCertificates(t *testing.T) {
test.AssertNotError(t, err, "Failed to unmarshal public JWK")
regA := &core.Registration{
ID: 1,
Contact: []core.AcmeURL{
core.AcmeURL(*emailA),
Contact: []*core.AcmeURL{
emailA,
},
Key: keyA,
}
regB := &core.Registration{
ID: 2,
Contact: []core.AcmeURL{
core.AcmeURL(*emailB),
Contact: []*core.AcmeURL{
emailB,
},
Key: keyB,
}

View File

@ -208,7 +208,7 @@ func TestURL(t *testing.T) {
jsonURL := fmt.Sprintf(`{"URL":"%s://%s%s?%s"}`, scheme, host, path, query)
badJSON := `{"URL":666}`
var url struct{ URL AcmeURL }
url := struct{ URL *AcmeURL }{URL: &AcmeURL{}}
err := json.Unmarshal([]byte(jsonURL), &url)
if err != nil {
t.Errorf("Error in json unmarshal: %v", err)
@ -231,7 +231,7 @@ func TestURL(t *testing.T) {
t.Errorf("Error in json marshal: %v", err)
}
if string(marshaledURL) != jsonURL {
t.Errorf("Improper marshaled URL: %s", string(marshaledURL))
t.Errorf("Expected marshaled url %#v, got %#v", jsonURL, string(marshaledURL))
}
}

View File

@ -204,7 +204,7 @@ type Registration struct {
Key jose.JsonWebKey `json:"key" db:"jwk"`
// Contact URIs
Contact []AcmeURL `json:"contact,omitempty" db:"contact"`
Contact []*AcmeURL `json:"contact,omitempty" db:"contact"`
// Agreement with terms of service
Agreement string `json:"agreement,omitempty" db:"agreement"`
@ -244,7 +244,7 @@ type Challenge struct {
Validated *time.Time `json:"validated,omitempty"`
// A URI to which a response can be POSTed
URI AcmeURL `json:"uri"`
URI *AcmeURL `json:"uri"`
// Used by simpleHttp, dvsni, and dns challenges
Token string `json:"token,omitempty"`

View File

@ -7,7 +7,6 @@ package core
import (
"encoding/json"
"net/url"
"testing"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
@ -23,16 +22,15 @@ func TestProblemDetails(t *testing.T) {
}
func TestRegistrationUpdate(t *testing.T) {
oldURL, _ := url.Parse("http://old.invalid")
newURL, _ := url.Parse("http://new.invalid")
oldURL, _ := ParseAcmeURL("http://old.invalid")
newURL, _ := ParseAcmeURL("http://new.invalid")
reg := Registration{
ID: 1,
Contact: []AcmeURL{AcmeURL(*oldURL)},
Contact: []*AcmeURL{oldURL},
Agreement: "",
}
update := Registration{
Contact: []AcmeURL{AcmeURL(*newURL)},
Contact: []*AcmeURL{newURL},
Agreement: "totally!",
}

View File

@ -19,13 +19,14 @@ import (
"encoding/json"
"errors"
"fmt"
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
blog "github.com/letsencrypt/boulder/log"
"hash"
"io"
"math/big"
"net/url"
"strings"
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
blog "github.com/letsencrypt/boulder/log"
)
// Package Variables Variables
@ -173,13 +174,22 @@ func KeyDigestEquals(j, k crypto.PublicKey) bool {
// AcmeURL is a URL that automatically marshal/unmarshal to JSON strings
type AcmeURL url.URL
func (u AcmeURL) String() string {
url := url.URL(u)
return url.String()
func ParseAcmeURL(s string) (*AcmeURL, error) {
u, err := url.Parse(s)
if err != nil {
return nil, err
}
au := AcmeURL(*u)
return &au, nil
}
func (u *AcmeURL) String() string {
uu := url.URL(*u)
return uu.String()
}
// PathSegments splits an AcmeURL into segments on the '/' characters
func (u AcmeURL) PathSegments() (segments []string) {
func (u *AcmeURL) PathSegments() (segments []string) {
segments = strings.Split(u.Path, "/")
if len(segments) > 0 && len(segments[0]) == 0 {
segments = segments[1:]
@ -188,8 +198,8 @@ func (u AcmeURL) PathSegments() (segments []string) {
}
// MarshalJSON encodes an AcmeURL for transfer
func (u AcmeURL) MarshalJSON() ([]byte, error) {
uu := url.URL(u)
func (u *AcmeURL) MarshalJSON() ([]byte, error) {
uu := url.URL(*u)
return json.Marshal(uu.String())
}

View File

@ -10,7 +10,6 @@ import (
"errors"
"fmt"
"net/mail"
"net/url"
"regexp"
"strconv"
"strings"
@ -49,7 +48,7 @@ func NewRegistrationAuthorityImpl() RegistrationAuthorityImpl {
var allButLastPathSegment = regexp.MustCompile("^.*/")
func lastPathSegment(url core.AcmeURL) string {
func lastPathSegment(url *core.AcmeURL) string {
return allButLastPathSegment.ReplaceAllString(url.Path, "")
}
@ -70,7 +69,7 @@ func validateEmail(address string, resolver core.DNSResolver) (err error) {
return
}
func validateContacts(contacts []core.AcmeURL, resolver core.DNSResolver) (err error) {
func validateContacts(contacts []*core.AcmeURL, resolver core.DNSResolver) (err error) {
for _, contact := range contacts {
switch contact.Scheme {
case "tel":
@ -181,8 +180,8 @@ func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization
// Construct all the challenge URIs
for i := range challenges {
// Ignoring these errors because we construct the URLs to be correct
challengeURI, _ := url.Parse(ra.AuthzBase + authz.ID + "?challenge=" + strconv.Itoa(i))
challenges[i].URI = core.AcmeURL(*challengeURI)
challengeURI, _ := core.ParseAcmeURL(ra.AuthzBase + authz.ID + "?challenge=" + strconv.Itoa(i))
challenges[i].URI = challengeURI
if !challenges[i].IsSane(false) {
// InternalServerError because we generated these challenges, they should

View File

@ -213,28 +213,28 @@ func assertAuthzEqual(t *testing.T, a1, a2 core.Authorization) {
}
func TestValidateContacts(t *testing.T) {
tel, _ := url.Parse("tel:")
ansible, _ := url.Parse("ansible:earth.sol.milkyway.laniakea/letsencrypt")
validEmail, _ := url.Parse("mailto:admin@email.com")
invalidEmail, _ := url.Parse("mailto:admin@example.com")
malformedEmail, _ := url.Parse("mailto:admin.com")
tel, _ := core.ParseAcmeURL("tel:")
ansible, _ := core.ParseAcmeURL("ansible:earth.sol.milkyway.laniakea/letsencrypt")
validEmail, _ := core.ParseAcmeURL("mailto:admin@email.com")
invalidEmail, _ := core.ParseAcmeURL("mailto:admin@example.com")
malformedEmail, _ := core.ParseAcmeURL("mailto:admin.com")
err := validateContacts([]core.AcmeURL{}, &mocks.MockDNS{})
err := validateContacts([]*core.AcmeURL{}, &mocks.MockDNS{})
test.AssertNotError(t, err, "No Contacts")
err = validateContacts([]core.AcmeURL{core.AcmeURL(*tel)}, &mocks.MockDNS{})
err = validateContacts([]*core.AcmeURL{tel}, &mocks.MockDNS{})
test.AssertNotError(t, err, "Simple Telephone")
err = validateContacts([]core.AcmeURL{core.AcmeURL(*validEmail)}, &mocks.MockDNS{})
err = validateContacts([]*core.AcmeURL{validEmail}, &mocks.MockDNS{})
test.AssertNotError(t, err, "Valid Email")
err = validateContacts([]core.AcmeURL{core.AcmeURL(*invalidEmail)}, &mocks.MockDNS{})
err = validateContacts([]*core.AcmeURL{invalidEmail}, &mocks.MockDNS{})
test.AssertError(t, err, "Invalid Email")
err = validateContacts([]core.AcmeURL{core.AcmeURL(*malformedEmail)}, &mocks.MockDNS{})
err = validateContacts([]*core.AcmeURL{malformedEmail}, &mocks.MockDNS{})
test.AssertError(t, err, "Malformed Email")
err = validateContacts([]core.AcmeURL{core.AcmeURL(*ansible)}, &mocks.MockDNS{})
err = validateContacts([]*core.AcmeURL{ansible}, &mocks.MockDNS{})
test.AssertError(t, err, "Unknown scehme")
}
@ -256,9 +256,9 @@ func TestValidateEmail(t *testing.T) {
func TestNewRegistration(t *testing.T) {
_, _, sa, ra := initAuthorities(t)
mailto, _ := url.Parse("mailto:foo@letsencrypt.org")
mailto, _ := core.ParseAcmeURL("mailto:foo@letsencrypt.org")
input := core.Registration{
Contact: []core.AcmeURL{core.AcmeURL(*mailto)},
Contact: []*core.AcmeURL{mailto},
Key: AccountKeyB,
}
@ -278,11 +278,11 @@ func TestNewRegistration(t *testing.T) {
func TestNewRegistrationNoFieldOverwrite(t *testing.T) {
_, _, _, ra := initAuthorities(t)
mailto, _ := url.Parse("mailto:foo@letsencrypt.org")
mailto, _ := core.ParseAcmeURL("mailto:foo@letsencrypt.org")
input := core.Registration{
ID: 23,
Key: AccountKeyC,
Contact: []core.AcmeURL{core.AcmeURL(*mailto)},
Contact: []*core.AcmeURL{mailto},
Agreement: "I agreed",
}
@ -304,9 +304,9 @@ func TestNewRegistrationNoFieldOverwrite(t *testing.T) {
func TestNewRegistrationBadKey(t *testing.T) {
_, _, _, ra := initAuthorities(t)
mailto, _ := url.Parse("mailto:foo@letsencrypt.org")
mailto, _ := core.ParseAcmeURL("mailto:foo@letsencrypt.org")
input := core.Registration{
Contact: []core.AcmeURL{core.AcmeURL(*mailto)},
Contact: []*core.AcmeURL{mailto},
Key: ShortKey,
}

View File

@ -12,7 +12,8 @@ import (
"crypto/x509/pkix"
"encoding/json"
"fmt"
"net/url"
"io/ioutil"
"testing"
"time"
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
@ -20,8 +21,6 @@ import (
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/mocks"
"github.com/letsencrypt/boulder/test"
"io/ioutil"
"testing"
)
var log = mocks.UseMockLog()
@ -72,10 +71,9 @@ func TestAddRegistration(t *testing.T) {
test.AssertEquals(t, dbReg.ID, expectedReg.ID)
test.Assert(t, core.KeyDigestEquals(dbReg.Key, expectedReg.Key), "Stored key != expected")
uu, err := url.Parse("test.com")
u := core.AcmeURL(*uu)
u, _ := core.ParseAcmeURL("test.com")
newReg := core.Registration{ID: reg.ID, Key: jwk, Contact: []core.AcmeURL{u}, Agreement: "yes"}
newReg := core.Registration{ID: reg.ID, Key: jwk, Contact: []*core.AcmeURL{u}, Agreement: "yes"}
err = sa.UpdateRegistration(newReg)
test.AssertNotError(t, err, fmt.Sprintf("Couldn't get registration with ID %v", reg.ID))
@ -139,9 +137,8 @@ func CreateDomainAuth(t *testing.T, domainName string, sa *SQLStorageAuthority)
test.Assert(t, authz.ID != "", "ID shouldn't be blank")
// prepare challenge for auth
uu, err := url.Parse(domainName)
u, err := core.ParseAcmeURL(domainName)
test.AssertNotError(t, err, "Couldn't parse domainName "+domainName)
u := core.AcmeURL(*uu)
chall := core.Challenge{Type: "simpleHttp", Status: core.StatusValid, URI: u, Token: "THISWOULDNTBEAGOODTOKEN"}
combos := make([][]int, 1)
combos[0] = []int{0, 1}

View File

@ -22,7 +22,7 @@ type BoulderTypeConverter struct{}
// ToDb converts a Boulder object to one suitable for the DB representation.
func (tc BoulderTypeConverter) ToDb(val interface{}) (interface{}, error) {
switch t := val.(type) {
case core.AcmeIdentifier, []core.Challenge, []core.AcmeURL, [][]int:
case core.AcmeIdentifier, []core.Challenge, []*core.AcmeURL, [][]int:
jsonBytes, err := json.Marshal(t)
if err != nil {
return nil, err
@ -48,7 +48,7 @@ func (tc BoulderTypeConverter) ToDb(val interface{}) (interface{}, error) {
// FromDb converts a DB representation back into a Boulder object.
func (tc BoulderTypeConverter) FromDb(target interface{}) (gorp.CustomScanner, bool) {
switch target.(type) {
case *core.AcmeIdentifier, *[]core.Challenge, *[]core.AcmeURL, *[][]int, core.JSONBuffer:
case *core.AcmeIdentifier, *[]core.Challenge, *[]*core.AcmeURL, *[][]int, core.JSONBuffer:
binder := func(holder, target interface{}) error {
s, ok := holder.(*string)
if !ok {

View File

@ -104,3 +104,22 @@ func TestOCSPStatus(t *testing.T) {
err = scanner.Binder(&marshaled, &out)
test.AssertMarshaledEquals(t, os, out)
}
func TestAcmeURLSlice(t *testing.T) {
tc := BoulderTypeConverter{}
var au, out []*core.AcmeURL
marshaledI, err := tc.ToDb(au)
test.AssertNotError(t, err, "Could not ToDb")
scanner, ok := tc.FromDb(&out)
test.Assert(t, ok, "FromDb failed")
if !ok {
t.FailNow()
return
}
marshaled := marshaledI.(string)
err = scanner.Binder(&marshaled, &out)
test.AssertMarshaledEquals(t, au, out)
}

View File

@ -14,7 +14,6 @@ import (
"html/template"
"io/ioutil"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
@ -98,16 +97,16 @@ func statusCodeFromError(err interface{}) int {
}
type requestEvent struct {
ID string `json:",omitempty"`
RealIP string `json:",omitempty"`
ForwardedFor string `json:",omitempty"`
Endpoint string `json:",omitempty"`
Method string `json:",omitempty"`
RequestTime time.Time `json:",omitempty"`
ResponseTime time.Time `json:",omitempty"`
Error string `json:",omitempty"`
Requester int64 `json:",omitempty"`
Contacts []core.AcmeURL `json:",omitempty"`
ID string `json:",omitempty"`
RealIP string `json:",omitempty"`
ForwardedFor string `json:",omitempty"`
Endpoint string `json:",omitempty"`
Method string `json:",omitempty"`
RequestTime time.Time `json:",omitempty"`
ResponseTime time.Time `json:",omitempty"`
Error string `json:",omitempty"`
Requester int64 `json:",omitempty"`
Contacts []*core.AcmeURL `json:",omitempty"`
Extra map[string]interface{} `json:",omitempty"`
}
@ -752,7 +751,7 @@ func (wfe *WebFrontEndImpl) challenge(authz core.Authorization, response http.Re
found := false
var challengeIndex int
for i, challenge := range authz.Challenges {
tempURL := url.URL(challenge.URI)
tempURL := challenge.URI
if tempURL.Path == request.URL.Path && tempURL.RawQuery == request.URL.RawQuery {
found = true
challengeIndex = i
@ -779,8 +778,7 @@ func (wfe *WebFrontEndImpl) challenge(authz core.Authorization, response http.Re
}
authzURL := wfe.AuthzBase + string(authz.ID)
challengeURL := url.URL(challenge.URI)
response.Header().Add("Location", challengeURL.String())
response.Header().Add("Location", challenge.URI.String())
response.Header().Set("Content-Type", "application/json")
response.Header().Add("Link", link(authzURL, "up"))
response.WriteHeader(http.StatusAccepted)
@ -850,8 +848,7 @@ func (wfe *WebFrontEndImpl) challenge(authz core.Authorization, response http.Re
}
authzURL := wfe.AuthzBase + string(authz.ID)
challengeURL := url.URL(challenge.URI)
response.Header().Add("Location", challengeURL.String())
response.Header().Add("Location", challenge.URI.String())
response.Header().Set("Content-Type", "application/json")
response.Header().Add("Link", link(authzURL, "up"))
response.WriteHeader(http.StatusAccepted)

View File

@ -680,7 +680,7 @@ func TestChallenge(t *testing.T) {
`), &key)
test.AssertNotError(t, err, "Could not unmarshal testing key")
challengeURL, _ := url.Parse("/acme/authz/asdf?challenge=foo")
challengeAcme, _ := core.ParseAcmeURL("/acme/authz/asdf?challenge=foo")
authz := core.Authorization{
ID: "asdf",
Identifier: core.AcmeIdentifier{
@ -690,15 +690,16 @@ func TestChallenge(t *testing.T) {
Challenges: []core.Challenge{
core.Challenge{
Type: "dns",
URI: core.AcmeURL(*challengeURL),
URI: challengeAcme,
},
},
RegistrationID: 1,
}
challengeURL := url.URL(*challengeAcme)
wfe.challenge(authz, responseWriter, &http.Request{
Method: "POST",
URL: challengeURL,
URL: &challengeURL,
Body: makeBody(signRequest(t, `{"resource":"challenge"}`, &wfe.nonceService)),
}, requestEvent{})
@ -818,8 +819,7 @@ func TestNewRegistration(t *testing.T) {
err = json.Unmarshal([]byte(responseWriter.Body.String()), &reg)
test.AssertNotError(t, err, "Couldn't unmarshal returned registration object")
test.Assert(t, len(reg.Contact) >= 1, "No contact field in registration")
uu := url.URL(reg.Contact[0])
test.AssertEquals(t, uu.String(), "tel:123456789")
test.AssertEquals(t, reg.Contact[0].String(), "tel:123456789")
test.AssertEquals(
t, responseWriter.Header().Get("Location"),