func (this *urlArgs) getScanVector() (timestamp.Vector, errors.Error) { var full_vector_data []*restArg var sparse_vector_data map[string]*restArg scan_vector_data_field, err := this.formValue(SCAN_VECTOR) if err != nil || scan_vector_data_field == "" { return nil, err } decoder := json.NewDecoder(strings.NewReader(scan_vector_data_field)) e := decoder.Decode(&full_vector_data) if e == nil { return makeFullVector(full_vector_data) } decoder = json.NewDecoder(strings.NewReader(scan_vector_data_field)) e = decoder.Decode(&sparse_vector_data) if e != nil { return nil, errors.NewServiceErrorBadValue(e, SCAN_VECTOR) } // Check that the rest data has the expected names for _, arg := range sparse_vector_data { if arg.Value == 0 || arg.Guard == "" { return nil, errors.NewServiceErrorBadValue(e, SCAN_VECTOR) } } return makeSparseVector(sparse_vector_data) }
func getCredentials(a httpRequestArgs, auths []string) (datastore.Credentials, errors.Error) { cred_data, err := a.getCredentials() if err != nil { return nil, err } if len(cred_data) > 0 { // Credentials are in request parameters: creds := datastore.Credentials{} for _, cred := range cred_data { user, user_ok := cred["user"] pass, pass_ok := cred["pass"] if user_ok && pass_ok { creds[user] = pass } else { err = errors.NewServiceErrorMissingValue("user or pass") break } } return creds, nil } if len(auths) > 0 { // Credentials are in http header: auth := auths[0] if strings.HasPrefix(auth, "Basic ") { encoded_creds := strings.Split(auth, " ")[1] decoded_creds, err := base64.StdEncoding.DecodeString(encoded_creds) if err != nil { return nil, errors.NewServiceErrorBadValue(err, CREDS) } // Authorization header is in format "user:pass" // per http://tools.ietf.org/html/rfc1945#section-10.2 u_details := strings.Split(string(decoded_creds), ":") creds := datastore.Credentials{} switch len(u_details) { case 2: creds[u_details[0]] = u_details[1] case 3: // Support usernames like "local:xxx" or "admin:xxx" creds[strings.Join(u_details[:2], ":")] = u_details[2] default: // Authorization header format is incorrect return nil, errors.NewServiceErrorBadValue(nil, CREDS) } return creds, nil } } return nil, err }
func makeSparseVector(args map[string]interface{}) (*scanVectorEntries, errors.Error) { entries := make([]timestamp.Entry, len(args)) i := 0 for key, arg := range args { index, err := strconv.Atoi(key) if err != nil { return nil, errors.NewServiceErrorBadValue(err, SCAN_VECTOR) } array, ok := arg.([]interface{}) if !ok { return nil, errors.NewServiceErrorTypeMismatch("scan vector entry", "two-element array") } sequenceNum, uuid, error := extractValues(array) if err != nil { return nil, error } entries[i] = &scanVectorEntry{ position: uint32(index), value: sequenceNum, guard: uuid, } i = i + 1 } return &scanVectorEntries{ entries: entries, }, nil }
// helper function to create a time.Duration instance from a given string. // There must be a unit - valid units are "ns", "us", "ms", "s", "m", "h" func newDuration(s string) (duration time.Duration, err errors.Error) { // Error if given string has no unit last_char := s[len(s)-1] if last_char != 's' && last_char != 'm' && last_char != 'h' { err = errors.NewServiceErrorBadValue(nil, fmt.Sprintf("duration value %s: missing or incorrect unit "+ "(valid units: ns, us, ms, s, m, h)", s)) } if err == nil { d, e := time.ParseDuration(s) if e != nil { err = errors.NewServiceErrorBadValue(e, "duration") } else { duration = d } } return }
func (this *urlArgs) getCredentials() ([]map[string]string, errors.Error) { var creds_data []map[string]string creds_field, err := this.formValue(CREDS) if err == nil && creds_field != "" { decoder := json.NewDecoder(strings.NewReader(creds_field)) e := decoder.Decode(&creds_data) if e != nil { err = errors.NewServiceErrorBadValue(e, CREDS) } } return creds_data, err }
// create a jsonArgs structure from the given http request. func newJsonArgs(req *http.Request) (*jsonArgs, errors.Error) { var p jsonArgs decoder := json.NewDecoder(req.Body) err := decoder.Decode(&p.args) if err != nil { return nil, errors.NewServiceErrorBadValue(err, "JSON request body") } for arg, _ := range p.args { if !isValidParameter(arg) { return nil, errors.NewServiceErrorUnrecognizedParameter(arg) } } p.req = req return &p, nil }
func (this *urlArgs) getTristate(f string) (value.Tristate, errors.Error) { tristate_value := value.NONE value_field, err := this.formValue(f) if err != nil { return tristate_value, err } if value_field == "" { return tristate_value, nil } bool_value, e := strconv.ParseBool(value_field) if e != nil { return tristate_value, errors.NewServiceErrorBadValue(e, f) } tristate_value = value.ToTristate(bool_value) return tristate_value, nil }
func (this *urlArgs) getScanVectors() (map[string]timestamp.Vector, errors.Error) { scan_vectors_data_field, err := this.formValue(SCAN_VECTORS) if err != nil || scan_vectors_data_field == "" { return nil, err } var target interface{} decoder := json.NewDecoder(strings.NewReader(scan_vectors_data_field)) e := decoder.Decode(&target) if e != nil { return nil, errors.NewServiceErrorBadValue(e, SCAN_VECTORS) } return getScanVectorsFromJSON(target) }
func (this *urlArgs) getStatement() (string, errors.Error) { statement, err := this.formValue(STATEMENT) if err != nil { return "", err } if statement == "" && this.req.Method == "POST" { bytes, err := ioutil.ReadAll(this.req.Body) if err != nil { return "", errors.NewServiceErrorBadValue(err, STATEMENT) } statement = string(bytes) } return statement, nil }
func (this *jsonArgs) getScanVector() (timestamp.Vector, errors.Error) { var type_ok bool scan_vector_data_field, in_request := this.getField(SCAN_VECTOR) if !in_request { return nil, nil } full_vector_data, type_ok := scan_vector_data_field.([]interface{}) if type_ok { if len(full_vector_data) != SCAN_VECTOR_SIZE { return nil, errors.NewServiceErrorTypeMismatch(SCAN_VECTOR, fmt.Sprintf("array of %d entries", SCAN_VECTOR_SIZE)) } entries := make([]timestamp.Entry, len(full_vector_data)) for index, arg := range full_vector_data { nextEntry, err := makeVectorEntry(index, arg) if err != nil { return nil, err } entries[index] = nextEntry } } sparse_vector_data, type_ok := scan_vector_data_field.(map[string]interface{}) if !type_ok { return nil, errors.NewServiceErrorTypeMismatch(SCAN_VECTOR, "array or map of { number, string }") } entries := make([]timestamp.Entry, len(sparse_vector_data)) i := 0 for key, arg := range sparse_vector_data { index, e := strconv.Atoi(key) if e != nil { return nil, errors.NewServiceErrorBadValue(e, SCAN_VECTOR) } nextEntry, err := makeVectorEntry(index, arg) if err != nil { return nil, err } entries[i] = nextEntry i = i + 1 } return &scanVectorEntries{ entries: entries, }, nil }
// makeSparseVector is used when the request contains a sparse entry arg func makeSparseVector(args map[string]*restArg) (*scanVectorEntries, errors.Error) { entries := make([]timestamp.Entry, len(args)) i := 0 for key, arg := range args { index, err := strconv.Atoi(key) if err != nil { return nil, errors.NewServiceErrorBadValue(err, SCAN_VECTOR) } entries[i] = &scanVectorEntry{ position: uint32(index), value: arg.Value, guard: arg.Guard, } i = i + 1 } return &scanVectorEntries{ entries: entries, }, nil }
// Positional args are of the form: args=json_list func (this *urlArgs) getPositionalArgs() (value.Values, errors.Error) { var positionalArgs value.Values args_field, err := this.formValue(ARGS) if err != nil || args_field == "" { return positionalArgs, err } var args []interface{} decoder := json.NewDecoder(strings.NewReader(args_field)) e := decoder.Decode(&args) if e != nil { return positionalArgs, errors.NewServiceErrorBadValue(e, ARGS) } positionalArgs = make([]value.Value, len(args)) // Put each element of args into positionalArgs for i, arg := range args { positionalArgs[i] = value.NewValue(arg) } return positionalArgs, nil }
func newHttpRequest(resp http.ResponseWriter, req *http.Request, bp BufferPool, size int) *httpRequest { var httpArgs httpRequestArgs var err errors.Error // Limit body size in case of denial-of-service attack req.Body = http.MaxBytesReader(resp, req.Body, int64(size)) e := req.ParseForm() if e != nil { err = errors.NewServiceErrorBadValue(e, "request form") } if err != nil && req.Method != "GET" && req.Method != "POST" { err = errors.NewServiceErrorHTTPMethod(req.Method) } err = contentNegotiation(resp, req) if err == nil { httpArgs, err = getRequestParams(req) } var statement string if err == nil { statement, err = httpArgs.getStatement() } var prepared *plan.Prepared if err == nil { prepared, err = getPrepared(httpArgs) plan, plan_err := getEncodedPlan(httpArgs) if err != nil && err.Code() == errors.NO_SUCH_PREPARED { if plan_err != nil { err = plan_err } if plan_err == nil && plan != nil { prepared = plan err = nil } } if err == nil && plan_err != nil { err = plan_err } if prepared != nil && plan != nil && prepared.EncodedPlan() != plan.EncodedPlan() { err = errors.NewPreparedEncodingMismatchError(prepared.Name()) } } if err == nil && statement == "" && prepared == nil { err = errors.NewServiceErrorMissingValue("statement or prepared") } var namedArgs map[string]value.Value if err == nil { namedArgs, err = httpArgs.getNamedArgs() } var positionalArgs value.Values if err == nil { positionalArgs, err = httpArgs.getPositionalArgs() } var namespace string if err == nil { namespace, err = httpArgs.getString(NAMESPACE, "") } var timeout time.Duration if err == nil { timeout, err = httpArgs.getDuration(TIMEOUT) } var max_parallelism int if err == nil { var maxp string maxp, err = httpArgs.getString(MAX_PARALLELISM, "") if err == nil && maxp != "" { var e error max_parallelism, e = strconv.Atoi(maxp) if e != nil { err = errors.NewServiceErrorBadValue(e, "max parallelism") } } } var readonly value.Tristate if err == nil { readonly, err = getReadonly(httpArgs, req.Method == "GET") } var metrics value.Tristate if err == nil { metrics, err = httpArgs.getTristate(METRICS) } var format Format if err == nil { format, err = getFormat(httpArgs) } if err == nil && format != JSON { err = errors.NewServiceErrorNotImplemented("format", format.String()) } var signature value.Tristate if err == nil { signature, err = httpArgs.getTristate(SIGNATURE) } var compression Compression if err == nil { compression, err = getCompression(httpArgs) } if err == nil && compression != NONE { err = errors.NewServiceErrorNotImplemented("compression", compression.String()) } var encoding Encoding if err == nil { encoding, err = getEncoding(httpArgs) } if err == nil && encoding != UTF8 { err = errors.NewServiceErrorNotImplemented("encoding", encoding.String()) } var pretty value.Tristate if err == nil { pretty, err = httpArgs.getTristate(PRETTY) } if err == nil && pretty == value.FALSE { err = errors.NewServiceErrorNotImplemented("pretty", "false") } var consistency *scanConfigImpl if err == nil { consistency, err = getScanConfiguration(httpArgs) } var creds datastore.Credentials if err == nil { creds, err = getCredentials(httpArgs, req.Header["Authorization"]) } client_id := "" if err == nil { client_id, err = getClientID(httpArgs) } base := server.NewBaseRequest(statement, prepared, namedArgs, positionalArgs, namespace, max_parallelism, readonly, metrics, signature, consistency, client_id, creds) rv := &httpRequest{ BaseRequest: *base, resp: resp, req: req, requestNotify: make(chan bool, 1), } rv.SetTimeout(rv, timeout) rv.writer = NewBufferedWriter(rv, bp) // Abort if client closes connection; alternatively, return when request completes. closeNotify := resp.(http.CloseNotifier).CloseNotify() closeNotifier := func() { select { case <-closeNotify: rv.Expire() return case <-rv.requestNotify: return } } go closeNotifier() if err != nil { rv.Fail(err) } return rv }