Пример #1
0
// ParseForm parses the raw query from the URL.
//
// For POST or PUT requests, it also parses the request body as a form.
// If the request Body's size has not already been limited by MaxBytesReader,
// the size is capped at 10MB.
//
// ParseMultipartForm calls ParseForm automatically.
// It is idempotent.
func (r *Request) ParseForm() (err os.Error) {
	if r.Form != nil {
		return
	}
	if r.URL != nil {
		r.Form, err = url.ParseQuery(r.URL.RawQuery)
	}
	if r.Method == "POST" || r.Method == "PUT" {
		if r.Body == nil {
			return os.NewError("missing form body")
		}
		ct := r.Header.Get("Content-Type")
		ct, _, err := mime.ParseMediaType(ct)
		switch {
		case ct == "text/plain" || ct == "application/x-www-form-urlencoded" || ct == "":
			var reader io.Reader = r.Body
			maxFormSize := int64(1<<63 - 1)
			if _, ok := r.Body.(*maxBytesReader); !ok {
				maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
				reader = io.LimitReader(r.Body, maxFormSize+1)
			}
			b, e := ioutil.ReadAll(reader)
			if e != nil {
				if err == nil {
					err = e
				}
				break
			}
			if int64(len(b)) > maxFormSize {
				return os.NewError("http: POST too large")
			}
			var newValues url.Values
			newValues, e = url.ParseQuery(string(b))
			if err == nil {
				err = e
			}
			if r.Form == nil {
				r.Form = make(url.Values)
			}
			// Copy values into r.Form. TODO: make this smoother.
			for k, vs := range newValues {
				for _, value := range vs {
					r.Form.Add(k, value)
				}
			}
		case ct == "multipart/form-data":
			// handled by ParseMultipartForm (which is calling us, or should be)
			// TODO(bradfitz): there are too many possible
			// orders to call too many functions here.
			// Clean this up and write more tests.
			// request_test.go contains the start of this,
			// in TestRequestMultipartCallOrder.
		default:
			return &badStringError{"unknown Content-Type", ct}
		}
	}
	return err
}
Пример #2
0
// ParseForm parses the raw query.
// For POST requests, it also parses the request body as a form.
// ParseMultipartForm calls ParseForm automatically.
// It is idempotent.
func (r *Request) ParseForm() (err os.Error) {
	if r.Form != nil {
		return
	}

	if r.URL != nil {
		r.Form, err = url.ParseQuery(r.URL.RawQuery)
	}
	if r.Method == "POST" {
		if r.Body == nil {
			return os.NewError("missing form body")
		}
		ct := r.Header.Get("Content-Type")
		switch strings.SplitN(ct, ";", 2)[0] {
		case "text/plain", "application/x-www-form-urlencoded", "":
			const maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
			b, e := ioutil.ReadAll(io.LimitReader(r.Body, maxFormSize+1))
			if e != nil {
				if err == nil {
					err = e
				}
				break
			}
			if int64(len(b)) > maxFormSize {
				return os.NewError("http: POST too large")
			}
			var newValues url.Values
			newValues, e = url.ParseQuery(string(b))
			if err == nil {
				err = e
			}
			if r.Form == nil {
				r.Form = make(url.Values)
			}
			// Copy values into r.Form. TODO: make this smoother.
			for k, vs := range newValues {
				for _, value := range vs {
					r.Form.Add(k, value)
				}
			}
		case "multipart/form-data":
			// handled by ParseMultipartForm
		default:
			return &badStringError{"unknown Content-Type", ct}
		}
	}
	return err
}
Пример #3
0
func TestParseForm(t *testing.T) {
	for i, test := range parseTests {
		form, err := url.ParseQuery(test.query)
		if err != nil {
			t.Errorf("test %d: Unexpected error: %v", i, err)
			continue
		}
		if len(form) != len(test.out) {
			t.Errorf("test %d: len(form) = %d, want %d", i, len(form), len(test.out))
		}
		for k, evs := range test.out {
			vs, ok := form[k]
			if !ok {
				t.Errorf("test %d: Missing key %q", i, k)
				continue
			}
			if len(vs) != len(evs) {
				t.Errorf("test %d: len(form[%q]) = %d, want %d", i, k, len(vs), len(evs))
				continue
			}
			for j, ev := range evs {
				if v := vs[j]; v != ev {
					t.Errorf("test %d: form[%q][%d] = %q, want %q", i, k, j, v, ev)
				}
			}
		}
	}
}
Пример #4
0
func handle(w http.ResponseWriter, r *http.Request) {
	params, err := url.ParseQuery(r.URL.RawQuery)
	check(err)
	w.Header().Add("Access-Control-Allow-Origin", "*")
	w.Header().Add(
		"Access-Control-Allow-Methods",
		"OPTIONS, HEAD, GET, POST, PUT, DELETE",
	)
	switch r.Method {
	case "OPTIONS":
	case "HEAD":
	case "GET":
		get(w, r)
	case "POST":
		if len(params["_method"]) > 0 && params["_method"][0] == "DELETE" {
			delete(w, r)
		} else {
			post(w, r)
		}
	case "DELETE":
		delete(w, r)
	default:
		http.Error(w, "501 Not Implemented", http.StatusNotImplemented)
	}
}
Пример #5
0
// Generates the canonical string-to-sign for dsocial services.
// You shouldn't need to use this directly.
func (p *signer) Canonicalize(req *http.Request) (out string, err os.Error) {
	fv, err := url.ParseQuery(req.URL.RawQuery)
	if err == nil {
		out = strings.Join([]string{req.Method, req.Host, req.URL.Path, SortedEscape(fv)}, "\n")
	}
	return
}
Пример #6
0
func UpdateLocation(w http.ResponseWriter, r *http.Request, validator auth.Validator, manager chan ManagerRequest) {
	auth_ok, client := validator.Validate(w, r)
	if !auth_ok {
		return
	}

	params, _ := url.ParseQuery(r.URL.RawQuery)
	location, err := ParseLocationFromRequest(params)
	if err != nil {
		http.Error(w, *err, http.StatusBadRequest)
		return
	}
	log.Printf("Got update request for %s with timestamp %d", *client, location.timestamp)

	// Reject timestamp from future.
	now := time.Seconds() * 1000
	if location.timestamp > now {
		location.timestamp = now
	}

	out := make(chan bool, 1)
	updateRequest := &UpdateLocationRequest{*client, location, out}
	manager <- updateRequest
	_ = <-out
	response := "ok"
	fmt.Fprintf(w, response)
}
Пример #7
0
func camliMode(req *http.Request) string {
	// TODO-GO: this is too hard to get at the GET Query args on a
	// POST request.
	m, err := url.ParseQuery(req.URL.RawQuery)
	if err != nil {
		return ""
	}
	if mode, ok := m["camli.mode"]; ok && len(mode) > 0 {
		return mode[0]
	}
	return ""
}
Пример #8
0
func (o *OAuthClient) GetAccessToken(requestToken *RequestToken, OAuthVerifier string) (*AccessToken, os.Error) {
	if requestToken == nil || requestToken.OAuthToken == "" || requestToken.OAuthTokenSecret == "" {
		return nil, os.NewError("Invalid Request token")
	}

	nonce := getNonce(40)
	params := map[string]string{
		"oauth_nonce":            nonce,
		"oauth_token":            requestToken.OAuthToken,
		"oauth_verifier":         OAuthVerifier,
		"oauth_signature_method": "HMAC-SHA1",
		"oauth_timestamp":        strconv.Itoa64(time.Seconds()),
		"oauth_consumer_key":     o.ConsumerKey,
		"oauth_version":          "1.0",
	}

	base := signatureBase("POST", requestTokenUrl.Raw, params)
	signature := signRequest(base, o.ConsumerSecret, requestToken.OAuthTokenSecret)
	params["oauth_signature"] = URLEscape(signature)

	authBuf := bytes.NewBufferString("OAuth ")
	i := 0
	for k, v := range params {
		authBuf.WriteString(fmt.Sprintf("%s=%q", k, v))
		if i < len(params)-1 {
			authBuf.WriteString(", ")
		}
		i++
	}
	request := httplib.Post(accessTokenUrl.Raw)
	request.Header("Authorization", authBuf.String())
	request.Body("")
	resp, err := request.AsString()
	tokens, err := url.ParseQuery(resp)
	if err != nil {
		return nil, err
	}

	at := AccessToken{
		OAuthTokenSecret: tokens["oauth_token_secret"][0],
		OAuthToken:       tokens["oauth_token"][0],
		UserId:           tokens["user_id"][0],
		ScreenName:       tokens["screen_name"][0],
	}
	return &at, nil

}
Пример #9
0
// Given the returned response from the access token request, pull out the
// access token and token secret.  Store a copy of any other values returned,
// too, since some services (like Twitter) return handy information such
// as the username.
func (c *UserConfig) parseAccessToken(response *http.Response) os.Error {
	defer response.Body.Close()
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return err
	}
	params, err := url.ParseQuery(string(body))
	tokenKey := params.Get("oauth_token")
	tokenSecret := params.Get("oauth_token_secret")
	if tokenKey == "" || tokenSecret == "" {
		return os.NewError("No token or secret found")
	}
	c.AccessTokenKey = tokenKey
	c.AccessTokenSecret = tokenSecret
	c.AccessValues = params
	return nil
}
Пример #10
0
func Poll(w http.ResponseWriter, r *http.Request, validator auth.Validator, manager chan ManagerRequest) {
	auth_ok, client := validator.Validate(w, r)
	if !auth_ok {
		return
	}

	params, _ := url.ParseQuery(r.URL.RawQuery)
	outFormat, err := query.GetQueryParam(params, "output")
	if err != nil {
		jsonFormat := "json"
		outFormat = &jsonFormat
	}
	timeout, err := query.GetInt32QueryParam(params, "timeout")
	if err != nil {
		timeout = kDefaultPollTimeoutSec
	}
	if timeout <= 0 || timeout > 60*60 {
		http.Error(w, fmt.Sprintf("Invalid timeout: %d", timeout), http.StatusBadRequest)
		return
	}
	log.Printf("Got poll request from %s with timeout %d", *client, timeout)

	out := make(chan *map[string]Location, 1)
	manager <- &WaitForUpdatesRequest{out}

	timeoutChan := make(chan bool, 1)
	go func() {
		time.Sleep(int64(timeout) * 1e9)
		timeoutChan <- true
	}()

	select {
	case locations := <-out:
		log.Printf("Sending update on poll request from %s", *client)
		if *outFormat == "proto" {
			w.Header().Add("Content-type", "application/octet-stream")
			w.Write(PrintLocationsAsProto(*locations))
		} else {
			w.Write([]byte(PrintLocationsAsJson(*locations)))
		}
	case <-timeoutChan:
		log.Printf("Poll request from %s timed out", *client)
		http.Error(w, "Poll request timed out, please try again", http.StatusRequestTimeout)
	}
}
Пример #11
0
func GetLocations(w http.ResponseWriter, r *http.Request, validator auth.Validator, manager chan ManagerRequest) {
	auth_ok, client := validator.Validate(w, r)
	if !auth_ok {
		return
	}
	log.Printf("Got locations request from %s", *client)

	params, _ := url.ParseQuery(r.URL.RawQuery)
	outFormat, err := query.GetQueryParam(params, "output")
	locations := GetAllLocations(manager)

	if err == nil && *outFormat == "proto" {
		w.Header().Add("Content-type", "application/octet-stream")
		w.Write(PrintLocationsAsProto(*locations))
	} else {
		w.Write([]byte(PrintLocationsAsJson(*locations)))
	}
}
Пример #12
0
func handleUploads(r *http.Request) (fileInfos []*FileInfo) {
	fileInfos = make([]*FileInfo, 0)
	mr, err := r.MultipartReader()
	check(err)
	r.Form, err = url.ParseQuery(r.URL.RawQuery)
	check(err)
	part, err := mr.NextPart()
	for err == nil {
		if name := part.FormName(); name != "" {
			if part.FileName() != "" {
				fileInfos = append(fileInfos, handleUpload(r, part))
			} else {
				r.Form[name] = append(r.Form[name], getFormValue(part))
			}
		}
		part, err = mr.NextPart()
	}
	return
}
Пример #13
0
// Given the returned response from a Request token request, parse out the
// appropriate request token and secret fields.
func (c *UserConfig) parseRequestToken(response *http.Response) os.Error {
	defer response.Body.Close()
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return err
	}
	params, err := url.ParseQuery(string(body))
	tokenKey := params.Get("oauth_token")
	tokenSecret := params.Get("oauth_token_secret")
	if tokenKey == "" || tokenSecret == "" {
		return os.NewError("No token or secret found")
	}
	c.RequestTokenKey = tokenKey
	c.RequestTokenSecret = tokenSecret
	if params.Get("oauth_callback_confirmed") == "false" {
		return os.NewError("OAuth callback not confirmed")
	}
	return nil
}
Пример #14
0
func JavascriptHandler(w http.ResponseWriter, r *http.Request) {
	params, _ := url.ParseQuery(r.URL.RawQuery)
	name, err := query.GetQueryParam(params, "name")
	if err != nil {
		http.Error(w, *err, http.StatusBadRequest)
		return
	}
	reg := regexp.MustCompile("[^a-z_]")
	if reg.MatchString(*name) {
		http.Error(w, "Bad filename", http.StatusBadRequest)
		return
	}
	data, osErr := ioutil.ReadFile(*name + ".js")
	if osErr != nil {
		http.Error(w, "File not found", http.StatusBadRequest)
		return
	}
	w.Header().Add("Content-type", "text/javascript")
	w.Write(data)
}
Пример #15
0
func (o *OAuthClient) GetRequestToken(callback string) *RequestToken {
	nonce := getNonce(40)
	params := map[string]string{
		"oauth_nonce":            nonce,
		"oauth_callback":         URLEscape(callback),
		"oauth_signature_method": "HMAC-SHA1",
		"oauth_timestamp":        strconv.Itoa64(time.Seconds()),
		"oauth_consumer_key":     o.ConsumerKey,
		"oauth_version":          "1.0",
	}

	base := signatureBase("POST", requestTokenUrl.Raw, params)
	signature := signRequest(base, o.ConsumerSecret, "")
	params["oauth_signature"] = URLEscape(signature)

	authBuf := bytes.NewBufferString("OAuth ")
	i := 0
	for k, v := range params {
		authBuf.WriteString(fmt.Sprintf("%s=%q", k, v))
		if i < len(params)-1 {
			authBuf.WriteString(", ")
		}
		i++
	}
	request := httplib.Post(requestTokenUrl.Raw)
	request.Header("Authorization", authBuf.String())
	request.Body("")
	resp, err := request.AsString()
	tokens, err := url.ParseQuery(resp)
	if err != nil {
		println(err.String())
	}

	confirmed, _ := strconv.Atob(tokens["oauth_callback_confirmed"][0])
	rt := RequestToken{
		OAuthTokenSecret:       tokens["oauth_token_secret"][0],
		OAuthToken:             tokens["oauth_token"][0],
		OAuthCallbackConfirmed: confirmed,
	}
	return &rt
}
Пример #16
0
// Modifies the request for signing
// if expiresIn is set to 0, a Timestamp will be used, otherwise an expiration.
func (p *signer) SignRequest(req *http.Request, expiresIn int64) {
	qstring, err := url.ParseQuery(req.URL.RawQuery)
	if err != nil {
		return
	}
	qstring["SignatureVersion"] = []string{DEFAULT_SIGNATURE_VERSION}
	if _, ok := qstring["SignatureMethod"]; !ok || len(qstring["SignatureMethod"]) == 0 {
		qstring["SignatureMethod"] = []string{DEFAULT_SIGNATURE_METHOD}
	}
	if expiresIn > 0 {
		qstring["Expires"] = []string{strconv.Itoa64(time.Seconds() + expiresIn)}
	} else {
		qstring["Timestamp"] = []string{time.UTC().Format(dm.UTC_DATETIME_FORMAT)}
	}
	qstring["Signature"] = nil, false
	qstring["DSOCAccessKeyId"] = []string{p.accessKey}

	var signature []byte
	req.URL.RawQuery = qstring.Encode()
	canonicalizedStringToSign, err := p.Canonicalize(req)
	if err != nil {
		return
	}
	//log.Printf("String-to-sign: '%s'", canonicalizedStringToSign)

	switch qstring["SignatureMethod"][0] {
	case SIGNATURE_METHOD_HMAC_SHA256:
		signature, err = p.SignEncoded(crypto.SHA256, canonicalizedStringToSign, base64.StdEncoding)
	case SIGNATURE_METHOD_HMAC_SHA1:
		signature, err = p.SignEncoded(crypto.SHA1, canonicalizedStringToSign, base64.StdEncoding)
	default:
		err = os.NewError("Unknown SignatureMethod:" + req.Form.Get("SignatureMethod"))
	}

	if err == nil {
		req.URL.RawQuery += "&" + url.Values{"Signature": []string{string(signature)}}.Encode()
		req.RawURL = req.URL.String()
	}
	return
}
Пример #17
0
// Verify that the url given match a successfull authentication
// Return:
// * true if authenticated, false otherwise
// * The Claimed identifier if authenticated
// * Eventually an error
func Verify(url_ string) (grant bool, identifier string, err error) {
	grant = false
	identifier = ""
	err = nil

	var values url.Values
	values, err = url.ParseQuery(url_)
	if err != nil {
		return false, "", err
	}

	// The value of "openid.return_to" matches the URL of the current request (Section 11.1)
	// To be implemented in a global way

	// Discovered information matches the information in the assertion (Section 11.2)

	// An assertion has not yet been accepted from this OP with the same value for "openid.response_nonce" (Section 11.3)

	// The signature on the assertion is valid and all fields that are required to be signed are signed (Section 11.4)

	return VerifyValues(values)
}
Пример #18
0
// ReadRequestBody parses the URL for the AJAX parameters
func (qx *queryCodec) ReadRequestBody(args interface{}) (err os.Error) {
	defer func() {
		qx.seq = 0
	}()
	if args == nil {
		if qx.Query.Req.Body != nil {
			qx.Query.Req.Body.Close()
		}
		return nil
	}

	a := args.(*Args)

	// Save request method (GET, POST, PUT, UPDATE, etc.)
	a.Method = qx.Query.Req.Method

	// Decode URL arguments
	a.Query, err = url.ParseQuery(qx.Query.Req.URL.RawQuery)
	if err != nil {
		return err
	}

	// Decode JSON body
	a.Body = make(map[string]interface{})
	if qx.Query.Req.Body != nil {
		dec := json.NewDecoder(qx.Query.Req.Body)
		// We don't care if the decode is successful.
		// The user will do their own complaining if they are missing expected arguments.
		dec.Decode(a.Body)
		qx.Query.Req.Body.Close()
	}

	// Read the cookies associated with the request
	a.Cookies = qx.Query.Req.Cookies()

	return nil
}
Пример #19
0
// Parse query string: /path?q=val1&id=val2
func getParams(r *http.Request) url.Values {
	p, _ := url.ParseQuery(r.URL.RawQuery)
	return p
}
Пример #20
0
func SmushFiles(response http.ResponseWriter, request *http.Request) {
	var requiredParams = []string{"name", "source"}

	if request.Method != "POST" {
		http.Error(response, "Must post from main Smush form", http.StatusInternalServerError)
		return
	}

	if !RequireParams(request, requiredParams) {
		http.Error(response, "Missing required params", http.StatusInternalServerError)
		return
	}

	var source []string

	source = request.Form["source"]
	sourceStrings := make([]string, len(source))
	i := 0

	// move the source urls into a new array so we can preserve the order, but skip blank entries
	for _, v := range source {
		if v != "" {
			sourceStrings[i] = v
			i++
		}
	}

	compileParamString := "compilation_level=SIMPLE_OPTIMIZATIONS"
	compileParamString += "&output_format=text"
	compileParamString += "&output_info=compiled_code"

	for _, v := range sourceStrings[:i] {
		compileParamString += "&code_url=" + v
	}

	compileParams, _ := url.ParseQuery(compileParamString)
	compileResponse, _ := http.PostForm(compilerURL, compileParams)

	result, _ := ReadWholeFile(compileResponse.Body)
	if len(result) == 1 {
		http.Error(response, "Something went wrong with the Closure Compiler", http.StatusInternalServerError)
		return
	}

	currentTime := time.LocalTime().Nanoseconds()

	dirName := "out/" + strconv.Itoa64(currentTime)
	fileName := dirName + "/" + request.Form["name"][0] + ".min.js"
	if err := os.Mkdir(dirName, uint32(0777)); err != nil {
		http.Error(response, "Couldn't create output folder", http.StatusInternalServerError)
		return
	}
	outputFile, err := os.Create(fileName)
	if err != nil {
		http.Error(response, "Couldn't create output file", http.StatusInternalServerError)
		return
	}
	_, err = outputFile.WriteString(result)
	if err != nil {
		http.Error(response, "Couldn't write output to file", http.StatusInternalServerError)
		return
	}

	http.Redirect(response, request, "/"+fileName, http.StatusFound)
}
Пример #21
0
// Checks whether the request has a signature, validates it if it does
// and returns an error if signature is present but not valid
func (p *signer) CheckSignature(req *http.Request) (hasSignature, validSignature bool, err os.Error) {
	qstring, err := url.ParseQuery(req.URL.RawQuery)
	if err != nil {
		err = ErrorInvalidURI
		return
	}
	if qstring.Get("Signature") == "" || qstring.Get("DSOCAccessKeyId") == "" {
		return
	}
	hasSignature = true
	now := time.UTC().Seconds()
	if expiresStr := qstring.Get("Expires"); expiresStr != "" {
		expiresAt, _ := strconv.Atoi64(expiresStr)
		if expiresAt < now {
			err = ErrorRequestExpired
			return
		}
	} else if timestampStr := qstring.Get("Timestamp"); timestampStr != "" {
		timestamp, _ := time.Parse(dm.UTC_DATETIME_FORMAT, timestampStr)
		if timestamp == nil || timestamp.Seconds()-MAX_VALID_TIMESTAMP_IN_SECONDS > now || timestamp.Seconds()+MAX_VALID_TIMESTAMP_IN_SECONDS < now {
			err = ErrorTimestampTooOld
			return
		}
	} else {
		err = ErrorExpiresOrTimestampRequired
		return
	}
	if qstring.Get("SignatureVersion") != "" && qstring.Get("SignatureVersion") != DEFAULT_SIGNATURE_VERSION {
		err = ErrorInvalidSignatureVersion
		return
	}
	var h crypto.Hash
	signatureMethod := qstring.Get("SignatureMethod")
	if signatureMethod == "" {
		signatureMethod = DEFAULT_SIGNATURE_METHOD
	}
	switch signatureMethod {
	case SIGNATURE_METHOD_HMAC_SHA256:
		h = crypto.SHA256
	case SIGNATURE_METHOD_HMAC_SHA1:
		h = crypto.SHA1
	default:
		err = ErrorInvalidSignatureMethod
		return
	}
	originalSignature := qstring.Get("Signature")
	qstring["Signature"] = nil, false
	qstring["DSOCAccessKeyId"] = []string{p.accessKey}

	var signature []byte
	req.URL.RawQuery = qstring.Encode()
	canonicalizedStringToSign, err := p.Canonicalize(req)
	if err != nil {
		return
	}
	//log.Printf("String-to-sign: '%s'", canonicalizedStringToSign)

	signature, err = p.SignEncoded(h, canonicalizedStringToSign, base64.StdEncoding)
	if err != nil || string(signature) != originalSignature {
		err = ErrorSignatureDoesNotMatch
	} else {
		validSignature = true
	}
	return
}
Пример #22
0
func (p *GoogleContactService) RetrieveGroups(client oauth2_client.OAuth2Client, ds DataStoreService, dsocialUserId string, next NextToken) ([]*Group, NextToken, os.Error) {
	var m url.Values
	if next == nil {
	} else if s, ok := next.(string); ok {
		if s != "" {
			if strings.HasPrefix(s, "https://www.google.com/") {
				uri, err := url.Parse(s)
				if err == nil {
					q, err := url.ParseQuery(uri.RawQuery)
					if err == nil {
						m = q
					}
				}
			}
			if m == nil {
				m = make(url.Values)
				m.Add("q", s)
			}
		}
	} else if maxResults, ok := next.(int); ok {
		m = make(url.Values)
		m.Add("max-results", strconv.Itoa(maxResults))
	} else if maxResults, ok := next.(int64); ok {
		m = make(url.Values)
		m.Add("max-results", strconv.Itoa64(maxResults))
	} else if gq, ok := next.(*google.GroupQuery); ok {
		m = make(url.Values)
		if gq.Alt != "" {
			m.Add("alt", gq.Alt)
		}
		if gq.Q != "" {
			m.Add("q", gq.Q)
		}
		if gq.MaxResults > 0 {
			m.Add("max-results", strconv.Itoa64(gq.MaxResults))
		}
		if gq.StartIndex > 0 {
			m.Add("start-index", strconv.Itoa64(gq.StartIndex))
		}
		if gq.UpdatedMin != "" {
			m.Add("updated-min", gq.UpdatedMin)
		}
		if gq.OrderBy != "" {
			m.Add("orderby", gq.OrderBy)
		}
		if gq.ShowDeleted {
			m.Add("showdeleted", "true")
		}
		if gq.RequireAllDeleted {
			m.Add("requirealldeleted", "true")
		}
		if gq.SortOrder != "" {
			m.Add("sortorder", gq.SortOrder)
		}
	}
	resp, err := google.RetrieveGroups(client, m)
	var theNextToken NextToken = nil
	if resp != nil && resp.Feed != nil && resp.Feed.Links != nil && len(resp.Feed.Links) > 0 {
		for _, link := range resp.Feed.Links {
			if link.Rel == "next" {
				theNextToken = link.Href
			}
		}
	}
	if resp == nil || resp.Feed == nil || resp.Feed.Entries == nil || len(resp.Feed.Entries) == 0 || err != nil {
		return make([]*Group, 0), theNextToken, err
	}
	groups := make([]*Group, len(resp.Feed.Entries))
	externalServiceId := p.ServiceId()
	userInfo, err := client.RetrieveUserInfo()
	externalUserId := userInfo.Guid()
	var useErr os.Error = nil
	for i, googleGroup := range resp.Feed.Entries {
		externalGroupId := googleGroup.GroupId()
		var origDsocialGroup *dm.Group = nil
		dsocialGroupId := ""
		if len(externalGroupId) > 0 {
			dsocialGroupId, err = ds.DsocialIdForExternalGroupId(externalServiceId, externalUserId, dsocialUserId, externalGroupId)
			if err != nil {
				if useErr == nil {
					useErr = err
				}
				continue
			}
			if dsocialGroupId != "" {
				origDsocialGroup, _, err = ds.RetrieveDsocialGroupForExternalGroup(externalServiceId, externalUserId, externalGroupId, dsocialUserId)
				if err != nil {
					if useErr == nil {
						useErr = err
					}
					continue
				}
			} else {
				ds.StoreExternalGroup(externalServiceId, externalUserId, dsocialUserId, externalGroupId, &googleGroup)
			}
		}
		var dsocialGroup *dm.Group = dm.GoogleGroupToDsocial(&googleGroup, origDsocialGroup, dsocialUserId)
		groups[i] = &Group{
			ExternalServiceId: p.ServiceId(),
			ExternalUserId:    googleGroup.GroupUserId(),
			ExternalGroupId:   googleGroup.GroupId(),
			DsocialUserId:     dsocialUserId,
			DsocialGroupId:    dsocialGroupId,
			Value:             dsocialGroup,
		}
	}
	return groups, theNextToken, useErr
}
Пример #23
0
func handler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	c.Infof("Requested URL: %v", r.URL)

	error := func(msg string) {
		reply := map[string]string{
			"error": msg,
		}
		resp, _ := json.Marshal(reply)

		w.WriteHeader(500)
		w.Write(resp)
	}

	query, _ := url.ParseQuery(r.URL.RawQuery)

	req_agent := r.Header.Get("User-Agent")
	req_url, ok_url := query["url"]

	if !ok_url {
		error("required parameters: url")
		return
	}

	c.Infof("Handling request for %s, agent: %s\n", req_url, req_agent)

	parsed_url, err := url.Parse(req_url[0])
	if err != nil {
		error("Invalid URL: " + err.String())
		return
	}

	robotsUrl := "http://" + parsed_url.Host + "/robots.txt"

	client := urlfetch.Client(c)
	resp, err := client.Get(robotsUrl)
	if err != nil {
		error("cannot fetch robots.txt: " + err.String())
		return
	}

	c.Infof("Fetched robots.txt: %s, status code: %s \n", robotsUrl, resp.StatusCode)

	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)

	robots, err := robotstxt.FromResponse(resp.StatusCode, string(body), true)
	if err != nil {
		error("cannot parse robots file: " + err.String())
		return
	}

	allow, err := robots.TestAgent(parsed_url.Path, req_agent)
	if (err != nil) || !allow {

		reply := map[string]string{
			"status": "disallowed",
		}
		resp, _ := json.Marshal(reply)

		w.WriteHeader(400)
		w.Write(resp)
		return
	}

	w.Header().Set("Location", req_url[0])
	w.WriteHeader(http.StatusFound)
}