Return-Path: Delivered-To: apmail-hbase-commits-archive@www.apache.org Received: (qmail 26982 invoked from network); 6 Oct 2010 17:21:55 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 6 Oct 2010 17:21:55 -0000 Received: (qmail 37175 invoked by uid 500); 6 Oct 2010 17:21:55 -0000 Delivered-To: apmail-hbase-commits-archive@hbase.apache.org Received: (qmail 37129 invoked by uid 500); 6 Oct 2010 17:21:54 -0000 Mailing-List: contact commits-help@hbase.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@hbase.apache.org Delivered-To: mailing list commits@hbase.apache.org Received: (qmail 37122 invoked by uid 99); 6 Oct 2010 17:21:54 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 06 Oct 2010 17:21:54 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 06 Oct 2010 17:21:53 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id CAA1A23888D7; Wed, 6 Oct 2010 17:21:32 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1005175 - in /hbase/trunk: ./ src/main/java/org/apache/hadoop/hbase/rest/ src/main/java/org/apache/hadoop/hbase/rest/client/ src/test/java/org/apache/hadoop/hbase/rest/ Date: Wed, 06 Oct 2010 17:21:32 -0000 To: commits@hbase.apache.org From: apurtell@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20101006172132.CAA1A23888D7@eris.apache.org> Author: apurtell Date: Wed Oct 6 17:21:32 2010 New Revision: 1005175 URL: http://svn.apache.org/viewvc?rev=1005175&view=rev Log: HBASE-2906 [rest/stargate] URI decoding in RowResource Modified: hbase/trunk/CHANGES.txt hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/RowResource.java hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/RowSpec.java hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/client/Client.java hbase/trunk/src/test/java/org/apache/hadoop/hbase/rest/TestRowResource.java Modified: hbase/trunk/CHANGES.txt URL: http://svn.apache.org/viewvc/hbase/trunk/CHANGES.txt?rev=1005175&r1=1005174&r2=1005175&view=diff ============================================================================== --- hbase/trunk/CHANGES.txt (original) +++ hbase/trunk/CHANGES.txt Wed Oct 6 17:21:32 2010 @@ -567,6 +567,7 @@ Release 0.21.0 - Unreleased HBASE-2753 Remove sorted() methods from Result now that Gets are Scans HBASE-3059 TestReadWriteConsistencyControl occasionally hangs (Hairong via Ryan) + HBASE-2906 [rest/stargate] URI decoding in RowResource IMPROVEMENTS HBASE-1760 Cleanup TODOs in HTable Modified: hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/RowResource.java URL: http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/RowResource.java?rev=1005175&r1=1005174&r2=1005175&view=diff ============================================================================== --- hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/RowResource.java (original) +++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/RowResource.java Wed Oct 6 17:21:32 2010 @@ -21,7 +21,6 @@ package org.apache.hadoop.hbase.rest; import java.io.IOException; -import java.net.URLDecoder; import java.util.List; import javax.ws.rs.Consumes; @@ -70,8 +69,11 @@ public class RowResource extends Resourc throws IOException { super(); this.tableName = table; - this.rowspec = new RowSpec(URLDecoder.decode(rowspec, - HConstants.UTF8_ENCODING)); + this.rowspec = new RowSpec(rowspec); + if (LOG.isDebugEnabled()) { + LOG.debug("new RowResource: table=" + this.tableName + "rowspec=" + + this.rowspec); + } if (versions != null) { this.rowspec.setMaxVersions(Integer.valueOf(versions)); } Modified: hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/RowSpec.java URL: http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/RowSpec.java?rev=1005175&r1=1005174&r2=1005175&view=diff ============================================================================== --- hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/RowSpec.java (original) +++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/RowSpec.java Wed Oct 6 17:21:32 2010 @@ -20,6 +20,8 @@ package org.apache.hadoop.hbase.rest; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; import java.util.Collection; import java.util.TreeSet; @@ -59,32 +61,29 @@ public class RowSpec { private int parseRowKeys(final String path, int i) throws IllegalArgumentException { - StringBuilder startRow = new StringBuilder(); - StringBuilder endRow = null; + String startRow = null, endRow = null; try { + StringBuilder sb = new StringBuilder(); char c; - boolean doEndRow = false; while (i < path.length() && (c = path.charAt(i)) != '/') { - if (c == ',') { - doEndRow = true; - i++; - break; - } - startRow.append(c); + sb.append(c); i++; } i++; - this.row = Bytes.toBytes(startRow.toString()); - if (doEndRow) { - endRow = new StringBuilder(); - while ((c = path.charAt(i)) != '/') { - endRow.append(c); - i++; - } - i++; + startRow = sb.toString(); + int idx = startRow.indexOf(','); + if (idx != -1) { + startRow = URLDecoder.decode(startRow.substring(0, idx), + HConstants.UTF8_ENCODING); + endRow = URLDecoder.decode(startRow.substring(idx + 1), + HConstants.UTF8_ENCODING); + } else { + startRow = URLDecoder.decode(startRow, HConstants.UTF8_ENCODING); } } catch (IndexOutOfBoundsException e) { throw new IllegalArgumentException(e); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); } // HBase does not support wildcards on row keys so we will emulate a // suffix glob by synthesizing appropriate start and end row keys for @@ -94,7 +93,7 @@ public class RowSpec { throw new IllegalArgumentException("invalid path: start row "+ "specified with wildcard"); this.row = Bytes.toBytes(startRow.substring(0, - startRow.lastIndexOf("*"))); + startRow.lastIndexOf("*"))); this.endRow = new byte[this.row.length + 1]; System.arraycopy(this.row, 0, this.endRow, 0, this.row.length); this.endRow[this.row.length] = (byte)255; @@ -115,37 +114,41 @@ public class RowSpec { try { char c; StringBuilder column = new StringBuilder(); - boolean hasColon = false; while (i < path.length() && (c = path.charAt(i)) != '/') { if (c == ',') { if (column.length() < 1) { throw new IllegalArgumentException("invalid path"); } - if (!hasColon) { - column.append(':'); + String s = URLDecoder.decode(column.toString(), + HConstants.UTF8_ENCODING); + if (!s.contains(":")) { + this.columns.add(Bytes.toBytes(s + ":")); + } else { + this.columns.add(Bytes.toBytes(s)); } - this.columns.add(Bytes.toBytes(column.toString())); - column = new StringBuilder(); - hasColon = false; + column.setLength(0); i++; continue; } - if (c == ':') { - hasColon = true; - } column.append(c); i++; } i++; // trailing list entry if (column.length() > 1) { - if (!hasColon) { - column.append(':'); + String s = URLDecoder.decode(column.toString(), + HConstants.UTF8_ENCODING); + if (!s.contains(":")) { + this.columns.add(Bytes.toBytes(s + ":")); + } else { + this.columns.add(Bytes.toBytes(s)); } - this.columns.add(Bytes.toBytes(column.toString())); } } catch (IndexOutOfBoundsException e) { throw new IllegalArgumentException(e); + } catch (UnsupportedEncodingException e) { + // shouldn't happen + throw new RuntimeException(e); } return i; } @@ -168,7 +171,8 @@ public class RowSpec { i++; } try { - time0 = Long.valueOf(stamp.toString()); + time0 = Long.valueOf(URLDecoder.decode(stamp.toString(), + HConstants.UTF8_ENCODING)); } catch (NumberFormatException e) { throw new IllegalArgumentException(e); } @@ -180,7 +184,8 @@ public class RowSpec { i++; } try { - time1 = Long.valueOf(stamp.toString()); + time1 = Long.valueOf(URLDecoder.decode(stamp.toString(), + HConstants.UTF8_ENCODING)); } catch (NumberFormatException e) { throw new IllegalArgumentException(e); } @@ -190,6 +195,9 @@ public class RowSpec { } } catch (IndexOutOfBoundsException e) { throw new IllegalArgumentException(e); + } catch (UnsupportedEncodingException e) { + // shouldn't happen + throw new RuntimeException(e); } if (time1 != 0) { startTime = time0; @@ -201,32 +209,45 @@ public class RowSpec { } private int parseQueryParams(final String path, int i) { - while (i < path.length()) { - char c = path.charAt(i); + if (i >= path.length()) { + return i; + } + StringBuilder query = new StringBuilder(); + try { + query.append(URLDecoder.decode(path.substring(i), + HConstants.UTF8_ENCODING)); + } catch (UnsupportedEncodingException e) { + // should not happen + throw new RuntimeException(e); + } + i += query.length(); + int j = 0; + while (j < query.length()) { + char c = query.charAt(j); if (c != '?' && c != '&') { break; } - if (++i > path.length()) { - break; + if (++j > query.length()) { + throw new IllegalArgumentException("malformed query parameter"); } - char what = path.charAt(i); - if (++i > path.length()) { + char what = query.charAt(j); + if (++j > query.length()) { break; } - c = path.charAt(i); + c = query.charAt(j); if (c != '=') { throw new IllegalArgumentException("malformed query parameter"); } - if (++i > path.length()) { + if (++j > query.length()) { break; } switch (what) { case 'm': { StringBuilder sb = new StringBuilder(); - while (i <= path.length()) { - c = path.charAt(i); + while (j <= query.length()) { + c = query.charAt(i); if (c < '0' || c > '9') { - i--; + j--; break; } sb.append(c); @@ -235,10 +256,10 @@ public class RowSpec { } break; case 'n': { StringBuilder sb = new StringBuilder(); - while (i <= path.length()) { - c = path.charAt(i); + while (j <= query.length()) { + c = query.charAt(i); if (c < '0' || c > '9') { - i--; + j--; break; } sb.append(c); Modified: hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java URL: http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java?rev=1005175&r1=1005174&r2=1005175&view=diff ============================================================================== --- hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java (original) +++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java Wed Oct 6 17:21:32 2010 @@ -22,6 +22,7 @@ package org.apache.hadoop.hbase.rest; import java.io.IOException; +import javax.ws.rs.Encoded; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; @@ -62,7 +63,9 @@ public class TableResource extends Resou @Path("{rowspec: .+}") public RowResource getRowResource( - final @PathParam("rowspec") String rowspec, + // We need the @Encoded decorator so Jersey won't urldecode before + // the RowSpec constructor has a chance to parse + final @PathParam("rowspec") @Encoded String rowspec, final @QueryParam("v") String versions) throws IOException { return new RowResource(table, rowspec, versions); } Modified: hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/client/Client.java URL: http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/client/Client.java?rev=1005175&r1=1005174&r2=1005175&view=diff ============================================================================== --- hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/client/Client.java (original) +++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/rest/client/Client.java Wed Oct 6 17:21:32 2010 @@ -93,11 +93,10 @@ public class Client { * @param cluster the cluster definition * @param method the transaction method * @param headers HTTP header values to send - * @param path the path + * @param path the properly urlencoded path * @return the HTTP response code * @throws IOException */ - @SuppressWarnings("deprecation") public int executePathOnly(Cluster cluster, HttpMethod method, Header[] headers, String path) throws IOException { IOException lastException; @@ -113,7 +112,7 @@ public class Client { sb.append("http://"); sb.append(cluster.lastHost); sb.append(path); - URI uri = new URI(sb.toString()); + URI uri = new URI(sb.toString(), true); return executeURI(method, headers, uri.toString()); } catch (IOException e) { lastException = e; @@ -126,14 +125,13 @@ public class Client { * Execute a transaction method given a complete URI. * @param method the transaction method * @param headers HTTP header values to send - * @param uri the URI + * @param uri a properly urlencoded URI * @return the HTTP response code * @throws IOException */ - @SuppressWarnings("deprecation") public int executeURI(HttpMethod method, Header[] headers, String uri) throws IOException { - method.setURI(new URI(uri)); + method.setURI(new URI(uri, true)); if (headers != null) { for (Header header: headers) { method.addRequestHeader(header); @@ -156,7 +154,7 @@ public class Client { * @param cluster the cluster definition * @param method the HTTP method * @param headers HTTP header values to send - * @param path the path or URI + * @param path the properly urlencoded path or URI * @return the HTTP response code * @throws IOException */ Modified: hbase/trunk/src/test/java/org/apache/hadoop/hbase/rest/TestRowResource.java URL: http://svn.apache.org/viewvc/hbase/trunk/src/test/java/org/apache/hadoop/hbase/rest/TestRowResource.java?rev=1005175&r1=1005174&r2=1005175&view=diff ============================================================================== --- hbase/trunk/src/test/java/org/apache/hadoop/hbase/rest/TestRowResource.java (original) +++ hbase/trunk/src/test/java/org/apache/hadoop/hbase/rest/TestRowResource.java Wed Oct 6 17:21:32 2010 @@ -124,7 +124,11 @@ public class TestRowResource extends HBa path.append(row); path.append('/'); path.append(column); - Response response = client.get(path.toString(), MIMETYPE_XML); + return getValueXML(path.toString()); + } + + Response getValueXML(String url) throws IOException { + Response response = client.get(url, MIMETYPE_XML); return response; } @@ -137,7 +141,11 @@ public class TestRowResource extends HBa path.append(row); path.append('/'); path.append(column); - Response response = client.get(path.toString(), MIMETYPE_PROTOBUF); + return getValuePB(path.toString()); + } + + Response getValuePB(String url) throws IOException { + Response response = client.get(url, MIMETYPE_PROTOBUF); return response; } @@ -150,6 +158,11 @@ public class TestRowResource extends HBa path.append(row); path.append('/'); path.append(column); + return putValueXML(path.toString(), table, row, column, value); + } + + Response putValueXML(String url, String table, String row, String column, + String value) throws IOException, JAXBException { RowModel rowModel = new RowModel(row); rowModel.addCell(new CellModel(Bytes.toBytes(column), Bytes.toBytes(value))); @@ -157,7 +170,7 @@ public class TestRowResource extends HBa cellSetModel.addRow(rowModel); StringWriter writer = new StringWriter(); marshaller.marshal(cellSetModel, writer); - Response response = client.put(path.toString(), MIMETYPE_XML, + Response response = client.put(url, MIMETYPE_XML, Bytes.toBytes(writer.toString())); Thread.yield(); return response; @@ -175,6 +188,18 @@ public class TestRowResource extends HBa assertEquals(Bytes.toString(cell.getValue()), value); } + void checkValueXML(String url, String table, String row, String column, + String value) throws IOException, JAXBException { + Response response = getValueXML(url); + assertEquals(response.getCode(), 200); + CellSetModel cellSet = (CellSetModel) + unmarshaller.unmarshal(new ByteArrayInputStream(response.getBody())); + RowModel rowModel = cellSet.getRows().get(0); + CellModel cell = rowModel.getCells().get(0); + assertEquals(Bytes.toString(cell.getColumn()), column); + assertEquals(Bytes.toString(cell.getValue()), value); + } + Response putValuePB(String table, String row, String column, String value) throws IOException { StringBuilder path = new StringBuilder(); @@ -184,12 +209,17 @@ public class TestRowResource extends HBa path.append(row); path.append('/'); path.append(column); + return putValuePB(path.toString(), table, row, column, value); + } + + Response putValuePB(String url, String table, String row, String column, + String value) throws IOException { RowModel rowModel = new RowModel(row); rowModel.addCell(new CellModel(Bytes.toBytes(column), Bytes.toBytes(value))); CellSetModel cellSetModel = new CellSetModel(); cellSetModel.addRow(rowModel); - Response response = client.put(path.toString(), MIMETYPE_PROTOBUF, + Response response = client.put(url, MIMETYPE_PROTOBUF, cellSetModel.createProtobufOutput()); Thread.yield(); return response; @@ -207,6 +237,18 @@ public class TestRowResource extends HBa assertEquals(Bytes.toString(cell.getValue()), value); } + void checkValuePB(String url, String table, String row, String column, + String value) throws IOException { + Response response = getValuePB(url); + assertEquals(response.getCode(), 200); + CellSetModel cellSet = new CellSetModel(); + cellSet.getObjectFromMessage(response.getBody()); + RowModel rowModel = cellSet.getRows().get(0); + CellModel cell = rowModel.getCells().get(0); + assertEquals(Bytes.toString(cell.getColumn()), column); + assertEquals(Bytes.toString(cell.getValue()), value); + } + void doTestDelete() throws IOException, JAXBException { Response response; @@ -300,19 +342,23 @@ public class TestRowResource extends HBa assertEquals(response.getCode(), 200); } - void doTestURLEncodedKey() throws IOException, JAXBException { - String encodedKey = URLEncoder.encode("http://www.google.com/", - HConstants.UTF8_ENCODING); + public void doTestURLEncodedKey() throws IOException, JAXBException { + String urlKey = "http://example.com/foo"; + StringBuilder path = new StringBuilder(); + path.append('/'); + path.append(TABLE); + path.append('/'); + path.append(URLEncoder.encode(urlKey, HConstants.UTF8_ENCODING)); + path.append('/'); + path.append(COLUMN_1); Response response; - response = putValueXML(TABLE, encodedKey, COLUMN_1, VALUE_1); - assertEquals(response.getCode(), 200); - response = putValuePB(TABLE, encodedKey, COLUMN_2, VALUE_2); + response = putValueXML(path.toString(), TABLE, urlKey, COLUMN_1, + VALUE_1); assertEquals(response.getCode(), 200); - checkValuePB(TABLE, encodedKey, COLUMN_1, VALUE_1); - checkValueXML(TABLE, encodedKey, COLUMN_2, VALUE_2); + checkValueXML(path.toString(), TABLE, urlKey, COLUMN_1, VALUE_1); } - public void testNoSuchCF() throws IOException, JAXBException { + public void doTestNoSuchCF() throws IOException, JAXBException { final String goodPath = "/" + TABLE + "/" + ROW_1 + "/" + CFA+":"; final String badPath = "/" + TABLE + "/" + ROW_1 + "/" + "BAD"; Response response = client.post(goodPath, MIMETYPE_BINARY, @@ -404,6 +450,7 @@ public class TestRowResource extends HBa doTestSingleCellGetPutBinary(); doTestSingleCellGetJSON(); doTestURLEncodedKey(); + doTestNoSuchCF(); doTestMultiCellGetPutXML(); doTestMultiCellGetPutPB(); }