gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

handlers.go (3742B)


      1 package pub
      2 
      3 import (
      4 	"context"
      5 	"encoding/json"
      6 	"errors"
      7 	"fmt"
      8 	"net/http"
      9 
     10 	"github.com/superseriousbusiness/activity/streams"
     11 )
     12 
     13 var ErrNotFound = errors.New("go-fed/activity: ActivityStreams data not found")
     14 
     15 // HandlerFunc determines whether an incoming HTTP request is an ActivityStreams
     16 // GET request, and if so attempts to serve ActivityStreams data.
     17 //
     18 // If an error is returned, then the calling function is responsible for writing
     19 // to the ResponseWriter as part of error handling.
     20 //
     21 // If 'isASRequest' is false and there is no error, then the calling function
     22 // may continue processing the request, and the HandlerFunc will not have
     23 // written anything to the ResponseWriter. For example, a webpage may be served
     24 // instead.
     25 //
     26 // If 'isASRequest' is true and there is no error, then the HandlerFunc
     27 // successfully served the request and wrote to the ResponseWriter.
     28 //
     29 // Callers are responsible for authorized access to this resource.
     30 type HandlerFunc func(c context.Context, w http.ResponseWriter, r *http.Request) (isASRequest bool, err error)
     31 
     32 // NewActivityStreamsHandler creates a HandlerFunc to serve ActivityStreams
     33 // requests which are coming from other clients or servers that wish to obtain
     34 // an ActivityStreams representation of data.
     35 //
     36 // Strips retrieved ActivityStreams values of sensitive fields ('bto' and 'bcc')
     37 // before responding with them. Sets the appropriate HTTP status code for
     38 // Tombstone Activities as well.
     39 //
     40 // Defaults to supporting content to be retrieved by HTTPS only.
     41 func NewActivityStreamsHandler(db Database, clock Clock) HandlerFunc {
     42 	return NewActivityStreamsHandlerScheme(db, clock, "https")
     43 }
     44 
     45 // NewActivityStreamsHandlerScheme creates a HandlerFunc to serve
     46 // ActivityStreams requests which are coming from other clients or servers that
     47 // wish to obtain an ActivityStreams representation of data provided by the
     48 // specified protocol scheme.
     49 //
     50 // Strips retrieved ActivityStreams values of sensitive fields ('bto' and 'bcc')
     51 // before responding with them. Sets the appropriate HTTP status code for
     52 // Tombstone Activities as well.
     53 //
     54 // Specifying the "scheme" allows for retrieving ActivityStreams content with
     55 // identifiers such as HTTP, HTTPS, or other protocol schemes.
     56 //
     57 // Returns ErrNotFound when the database does not retrieve any data and no
     58 // errors occurred during retrieval.
     59 func NewActivityStreamsHandlerScheme(db Database, clock Clock, scheme string) HandlerFunc {
     60 	return func(c context.Context, w http.ResponseWriter, r *http.Request) (isASRequest bool, err error) {
     61 		// Do nothing if it is not an ActivityPub GET request
     62 		if !isActivityPubGet(r) {
     63 			return
     64 		}
     65 		isASRequest = true
     66 		id := requestId(r, scheme)
     67 
     68 		var unlock func()
     69 
     70 		// Lock and obtain a copy of the requested ActivityStreams value
     71 		unlock, err = db.Lock(c, id)
     72 		if err != nil {
     73 			return
     74 		}
     75 		// WARNING: Unlock not deferred
     76 		t, err := db.Get(c, id)
     77 		unlock() // unlock even on error
     78 		if err != nil {
     79 			return
     80 		}
     81 		// Unlock must have been called by this point and in every
     82 		// branch above
     83 		if t == nil {
     84 			err = ErrNotFound
     85 			return
     86 		}
     87 		// Remove sensitive fields.
     88 		clearSensitiveFields(t)
     89 		// Serialize the fetched value.
     90 		m, err := streams.Serialize(t)
     91 		if err != nil {
     92 			return
     93 		}
     94 		raw, err := json.Marshal(m)
     95 		if err != nil {
     96 			return
     97 		}
     98 		// Construct the response.
     99 		addResponseHeaders(w.Header(), clock, raw)
    100 		// Write the response.
    101 		if streams.IsOrExtendsActivityStreamsTombstone(t) {
    102 			w.WriteHeader(http.StatusGone)
    103 		} else {
    104 			w.WriteHeader(http.StatusOK)
    105 		}
    106 		n, err := w.Write(raw)
    107 		if err != nil {
    108 			return
    109 		} else if n != len(raw) {
    110 			err = fmt.Errorf("only wrote %d of %d bytes", n, len(raw))
    111 			return
    112 		}
    113 		return
    114 	}
    115 }