示例#1
0
// If we hit an error and there is a pending transaction, rollback
// the transaction before returning. The client does not have to
// deal with cleaning up transaction state.
func makeResultFromError(planMaker *planner, err error) driver.Result {
	if planMaker.txn != nil {
		if err != errTransactionAborted {
			planMaker.txn.Cleanup(err)
		}
		// This transaction will normally get marked aborted as part of
		// Cleanup above, but we do it explicitly here because edge cases
		// exist:
		// (1)
		// BEGIN
		// <some operation which is implemented using CPut, which fails>
		// (2)
		// BEGIN
		// <syntax error>
		// Both cases will not write any intents, and so client.Txn will
		// not actually send an EndTransaction, and rightly so.
		// Unfortunately, we depend on txn.Proto.Status being equivalent to
		// our SQL transaction's status, and in these cases, our SQL
		// transaction is aborted.
		planMaker.txn.Proto.Status = proto.ABORTED
	}
	var errProto proto.Error
	errProto.SetResponseGoError(err)
	return driver.Result{Error: &errProto}
}
示例#2
0
// ServeHTTP serves the SQL API by treating the request URL path
// as the method, the request body as the arguments, and sets the
// response body as the method reply. The request body is unmarshalled
// into arguments based on the Content-Type request header. Protobuf
// and JSON-encoded requests are supported. The response body is
// encoded according to the request's Accept header, or if not
// present, in the same format as the request's incoming Content-Type
// header.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	method := r.URL.Path
	if !strings.HasPrefix(method, driver.Endpoint) {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	// Check TLS settings.
	authenticationHook, err := security.AuthenticationHook(s.context.Insecure, r.TLS)
	if err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	method = strings.TrimPrefix(method, driver.Endpoint)
	if method != driver.Execute.String() {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	// Unmarshal the request.
	reqBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var args driver.Request
	if err := util.UnmarshalRequest(r, reqBody, &args, allowedEncodings); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Check request user against client certificate user.
	if err := authenticationHook(&args); err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	// Send the Request for SQL execution and set the application-level error
	// on the reply.
	reply, err := s.exec(args)
	if err != nil {
		errProto := proto.Error{}
		errProto.SetResponseGoError(err)
		reply.Error = &errProto
	}

	// Marshal the response.
	body, contentType, err := util.MarshalResponse(r, &reply, allowedEncodings)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set(util.ContentTypeHeader, contentType)
	w.Write(body)
}
示例#3
0
// If we hit an error and there is a pending transaction, rollback
// the transaction before returning. The client does not have to
// deal with cleaning up transaction state.
func makeResultFromError(planMaker *planner, err error) driver.Result {
	if planMaker.txn != nil {
		if err != errTransactionAborted {
			planMaker.txn.Cleanup(err)
		}
	}
	var errProto proto.Error
	errProto.SetResponseGoError(err)
	return driver.Result{Error: &errProto}
}
示例#4
0
// If we hit an error and there is a pending transaction, rollback
// the transaction before returning. The client does not have to
// deal with cleaning up transaction state.
func rollbackTxnAndReturnResultWithError(planMaker *planner, err error) driver.Result {
	if planMaker.txn != nil {
		// What do we do with a rollback error? This is an internally
		// initiated rollback that the client is unaware of. Reporting it
		// will only cause confusion. Not reporting it could leave a transaction
		// pending, but that will get GCed eventually.
		_ = planMaker.txn.Rollback()
	}
	var errProto proto.Error
	errProto.SetResponseGoError(err)
	return driver.Result{Error: &errProto}
}