Skip to content

Commit

Permalink
server, docs: change rowBin to request. (pingcap#5983)
Browse files Browse the repository at this point in the history
  • Loading branch information
zimulala authored Mar 9, 2018
1 parent 3ac2b34 commit 831c93f
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 19 deletions.
6 changes: 4 additions & 2 deletions docs/tidb_http_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,11 @@ timezone.*
curl http://{TiDBIP}:10080/settings
```

1. Get the column value by an encoded row and some information that can be obtained from a column of the table schema information.
1. Get the column value by an encoded row and some information that can be obtained from a column of the table schema information.

Argument example: rowBin=base64_encoded_row_value

```shell
curl http://{TiDBIP}:10080/tables/{colID}/{colFlag}/{colLen}/{rowBin}
curl http://{TiDBIP}:10080/tables/{colID}/{colFlag}/{colLen}?rowBin={val}
```
*Hint: For the column which field type is timezone dependent, e.g. `timestamp`, convert its value to UTC timezone.*
53 changes: 38 additions & 15 deletions server/http_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,25 @@ func (vh valueHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}

// Get binary.
bin := params[pRowBin]
// Get the unchanged binary.
if req.URL == nil {
err = errors.BadRequestf("Invalid URL")
writeError(w, err)
return
}
values := make(url.Values)
shouldUnescape := false
err = parseQuery(req.URL.RawQuery, values, shouldUnescape)
if err != nil {
writeError(w, err)
return
}
if len(values[pRowBin]) != 1 {
err = errors.BadRequestf("Invalid Query:%v", values[pRowBin])
writeError(w, err)
return
}
bin := values[pRowBin][0]
valData, err := base64.StdEncoding.DecodeString(bin)
if err != nil {
writeError(w, err)
Expand Down Expand Up @@ -882,11 +899,13 @@ func (r RegionFrameRange) lastTableID() int64 {
return r.last.TableID
}

// parseQuery is used to parse query string in URL, due to golang http package can not distinguish
// parseQuery is used to parse query string in URL with shouldUnescape, due to golang http package can not distinguish
// query like "?a=" and "?a". We rewrite it to separate these two queries. e.g.
// "?a=" which means that a is an empty string "";
// "?a" which means that a is null.
func parseQuery(query string, m url.Values) error {
// If shouldUnescape is true, we use QueryUnescape to handle keys and values that will be put in m.
// If shouldUnescape is false, we don't use QueryUnescap to handle.
func parseQuery(query string, m url.Values, shouldUnescape bool) error {
var err error
for query != "" {
key := query
Expand All @@ -901,19 +920,23 @@ func parseQuery(query string, m url.Values) error {
if i := strings.Index(key, "="); i >= 0 {
value := ""
key, value = key[:i], key[i+1:]
key, err = url.QueryUnescape(key)
if err != nil {
return errors.Trace(err)
}
value, err = url.QueryUnescape(value)
if err != nil {
return errors.Trace(err)
if shouldUnescape {
key, err = url.QueryUnescape(key)
if err != nil {
return errors.Trace(err)
}
value, err = url.QueryUnescape(value)
if err != nil {
return errors.Trace(err)
}
}
m[key] = append(m[key], value)
} else {
key, err = url.QueryUnescape(key)
if err != nil {
return errors.Trace(err)
if shouldUnescape {
key, err = url.QueryUnescape(key)
if err != nil {
return errors.Trace(err)
}
}
if _, ok := m[key]; !ok {
m[key] = nil
Expand All @@ -937,7 +960,7 @@ func (h mvccTxnHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
break
}
values := make(url.Values)
err = parseQuery(req.URL.RawQuery, values)
err = parseQuery(req.URL.RawQuery, values, true)
if err == nil {
data, err = h.handleMvccGetByIdx(params, values)
}
Expand Down
15 changes: 14 additions & 1 deletion server/http_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,9 +363,10 @@ func (ts *HTTPHandlerTestSuite) TestDecodeColumnValue(c *C) {
bs, err := tablecodec.EncodeRow(sc, row, colIDs, nil, nil)
c.Assert(err, IsNil)
c.Assert(bs, NotNil)
bin := base64.StdEncoding.EncodeToString(bs)

unitTest := func(col *column) {
url := fmt.Sprintf("http://127.0.0.1:10090/tables/%d/%v/%d/%d/%s", col.id, col.tp.Tp, col.tp.Flag, col.tp.Flen, base64.StdEncoding.EncodeToString(bs))
url := fmt.Sprintf("http://127.0.0.1:10090/tables/%d/%v/%d/%d?rowBin=%s", col.id, col.tp.Tp, col.tp.Flag, col.tp.Flen, bin)
resp, err := http.Get(url)
c.Assert(err, IsNil, Commentf("url:%s", url))
decoder := json.NewDecoder(resp.Body)
Expand All @@ -380,6 +381,18 @@ func (ts *HTTPHandlerTestSuite) TestDecodeColumnValue(c *C) {
for _, col := range cols {
unitTest(col)
}

// Test bin has `+`.
// 2018-03-08 16:01:00.315313
bin = "CAIIyAEIBAIGYWJjCAYGAQCBCAgJsZ+TgISg1M8Z"
row[3] = types.NewTimeDatum(types.Time{Time: types.FromGoTime(time.Date(2018, 3, 8, 16, 1, 0, 315313000, time.UTC)), Fsp: 6, Type: mysql.TypeTimestamp})
unitTest(cols[3])

// Test bin has `/`.
// 2018-03-08 02:44:46.409199
bin = "CAIIyAEIBAIGYWJjCAYGAQCBCAgJ7/yY8LKF1M8Z"
row[3] = types.NewTimeDatum(types.Time{Time: types.FromGoTime(time.Date(2018, 3, 8, 2, 44, 46, 409199000, time.UTC)), Fsp: 6, Type: mysql.TypeTimestamp})
unitTest(cols[3])
}

func (ts *HTTPHandlerTestSuite) TestGetIndexMVCC(c *C) {
Expand Down
2 changes: 1 addition & 1 deletion server/http_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (s *Server) startHTTPServer() {
router.Handle("/schema", schemaHandler{tikvHandlerTool})
router.Handle("/schema/{db}", schemaHandler{tikvHandlerTool})
router.Handle("/schema/{db}/{table}", schemaHandler{tikvHandlerTool})
router.Handle("/tables/{colID}/{colTp}/{colFlag}/{colLen}/{rowBin}", valueHandler{})
router.Handle("/tables/{colID}/{colTp}/{colFlag}/{colLen}", valueHandler{})
if s.cfg.Store == "tikv" {
// HTTP path for tikv
router.Handle("/tables/{db}/{table}/regions", tableHandler{tikvHandlerTool, opTableRegions})
Expand Down

0 comments on commit 831c93f

Please sign in to comment.