1 30 31 32 package org.hsqldb; 33 34 import java.io.BufferedOutputStream ; 35 import java.io.DataInputStream ; 36 import java.io.File ; 37 import java.io.FileInputStream ; 38 import java.io.IOException ; 39 import java.io.InputStream ; 40 import java.io.OutputStream ; 41 import java.net.HttpURLConnection ; 42 import java.net.Socket ; 43 44 import org.hsqldb.lib.ArrayUtil; 45 import org.hsqldb.lib.InOutUtil; 46 import org.hsqldb.persist.HsqlDatabaseProperties; 47 import org.hsqldb.resources.BundleHandler; 48 import org.hsqldb.rowio.RowInputBinary; 49 import org.hsqldb.rowio.RowOutputBinary; 50 51 58 76 class WebServerConnection implements Runnable { 77 78 static final String ENCODING = "8859_1"; 79 private Socket socket; 80 private WebServer server; 81 private static final int REQUEST_TYPE_BAD = 0; 82 private static final int REQUEST_TYPE_GET = 1; 83 private static final int REQUEST_TYPE_HEAD = 2; 84 private static final int REQUEST_TYPE_POST = 3; 85 private static final String HEADER_OK = "HTTP/1.0 200 OK"; 86 private static final String HEADER_BAD_REQUEST = 87 "HTTP/1.0 400 Bad Request"; 88 private static final String HEADER_NOT_FOUND = "HTTP/1.0 404 Not Found"; 89 private static final String HEADER_FORBIDDEN = "HTTP/1.0 403 Forbidden"; 90 static final int BUFFER_SIZE = 256; 91 private RowOutputBinary rowOut = new RowOutputBinary(BUFFER_SIZE); 92 private RowInputBinary rowIn = new RowInputBinary(rowOut); 93 94 static final byte[] BYTES_GET = "GET".getBytes(); 96 static final byte[] BYTES_HEAD = "HEAD".getBytes(); 97 static final byte[] BYTES_POST = "POST".getBytes(); 98 static final byte[] BYTES_CONTENT = "Content-Length: ".getBytes(); 99 static final byte[] BYTES_WHITESPACE = new byte[] { 100 (byte) ' ', (byte) '\t' 101 }; 102 103 private static final int hnd_content_types = 105 BundleHandler.getBundleHandle("content-types", null); 106 107 116 WebServerConnection(Socket socket, WebServer server) { 117 this.server = server; 118 this.socket = socket; 119 } 120 121 128 private String getMimeTypeString(String name) { 129 130 int pos; 131 String key; 132 String mimeType; 133 134 if (name == null) { 135 return ServerConstants.SC_DEFAULT_WEB_MIME; 136 } 137 138 pos = name.lastIndexOf('.'); 139 key = null; 140 mimeType = null; 141 142 if (pos >= 0) { 144 key = name.substring(pos).toLowerCase(); 145 mimeType = server.serverProperties.getProperty(key); 146 } 147 148 if (mimeType == null && key.length() > 1) { 150 mimeType = BundleHandler.getString(hnd_content_types, 151 key.substring(1)); 152 } 153 154 return mimeType == null ? ServerConstants.SC_DEFAULT_WEB_MIME 155 : mimeType; 156 } 157 158 165 public void run() { 166 167 try { 168 DataInputStream inStream = 169 new DataInputStream (socket.getInputStream()); 170 int count; 171 String request; 172 String name = null; 173 int method = REQUEST_TYPE_BAD; 174 int len = -1; 175 176 do { 178 count = InOutUtil.readLine(inStream, rowOut); 179 180 if (count == 0) { 181 throw new Exception (); 182 } 183 } while (count < 2); 184 185 byte[] byteArray = rowOut.getBuffer(); 186 int offset = rowOut.size() - count; 187 188 if (ArrayUtil.containsAt(byteArray, offset, BYTES_POST)) { 189 method = REQUEST_TYPE_POST; 190 offset += BYTES_POST.length; 191 } else if (ArrayUtil.containsAt(byteArray, offset, BYTES_GET)) { 192 method = REQUEST_TYPE_GET; 193 offset += BYTES_GET.length; 194 } else if (ArrayUtil.containsAt(byteArray, offset, BYTES_HEAD)) { 195 method = REQUEST_TYPE_HEAD; 196 offset += BYTES_HEAD.length; 197 } else { 198 throw new Exception (); 199 } 200 201 count = ArrayUtil.countStartElementsAt(byteArray, offset, 202 BYTES_WHITESPACE); 203 204 if (count == 0) { 205 throw new Exception (); 206 } 207 208 offset += count; 209 count = ArrayUtil.countNonStartElementsAt(byteArray, offset, 210 BYTES_WHITESPACE); 211 name = new String (byteArray, offset, count, ENCODING); 212 213 switch (method) { 214 215 case REQUEST_TYPE_BAD : 216 processError(REQUEST_TYPE_BAD); 217 break; 218 219 case REQUEST_TYPE_GET : 220 processGet(name, true); 221 break; 222 223 case REQUEST_TYPE_HEAD : 224 processGet(name, false); 225 break; 226 227 case REQUEST_TYPE_POST : 228 processPost(inStream, name); 229 break; 230 } 231 232 inStream.close(); 233 socket.close(); 234 } catch (Exception e) { 235 server.printStackTrace(e); 236 } 237 } 238 239 243 private void processPost(InputStream inStream, 244 String name) throws HsqlException, IOException { 245 246 try { 248 249 InOutUtil.readLine(inStream, rowOut); 251 252 int count = InOutUtil.readLine(inStream, rowOut); 254 int offset = rowOut.size() - count; 255 256 byte[] byteArray = rowOut.getBuffer(); 259 260 if (!ArrayUtil.containsAt(byteArray, offset, BYTES_CONTENT)) { 261 throw new Exception (); 262 } 263 264 count -= BYTES_CONTENT.length; 265 offset += BYTES_CONTENT.length; 266 267 String lenStr = new String (byteArray, offset, count - 2); 269 int length = Integer.parseInt(lenStr); 270 271 InOutUtil.readLine(inStream, rowOut); 272 } catch (Exception e) { 273 processError(HttpURLConnection.HTTP_BAD_REQUEST); 274 275 return; 276 } 277 278 processQuery(inStream); 279 } 280 281 288 void processQuery(InputStream inStream) { 289 290 try { 291 Result resultIn = Result.read(rowIn, 292 new DataInputStream (inStream)); 293 294 Result resultOut; 296 297 if (resultIn.mode == ResultConstants.SQLCONNECT) { 298 try { 299 int dbID = server.getDBID(resultIn.subSubString); 300 Session session = DatabaseManager.newSession(dbID, 301 resultIn.getMainString(), resultIn.getSubString()); 302 303 resultOut = new Result(ResultConstants.UPDATECOUNT); 304 resultOut.databaseID = dbID; 305 resultOut.sessionID = session.getId(); 306 } catch (HsqlException e) { 307 resultOut = new Result(e, null); 308 } catch (RuntimeException e) { 309 resultOut = new Result(e, null); 310 } 311 } else { 312 int dbID = resultIn.databaseID; 313 Session session = DatabaseManager.getSession(dbID, 314 resultIn.sessionID); 315 316 resultOut = 317 session == null 318 ? new Result(Trace.error(Trace.DATABASE_NOT_EXISTS), null) 319 : session.execute(resultIn); 320 } 321 322 rowOut.reset(); 324 resultOut.write(rowOut); 325 326 OutputStream outStream = socket.getOutputStream(); 327 String header = getHead(HEADER_OK, false, 328 "application/octet-stream", 329 rowOut.size()); 330 331 outStream.write(header.getBytes(ENCODING)); 332 outStream.write(rowOut.getOutputStream().getBuffer(), 0, 333 rowOut.getOutputStream().size()); 334 outStream.flush(); 335 outStream.close(); 336 } catch (Exception e) { 337 server.printStackTrace(e); 338 } 339 } 340 341 347 private void processGet(String name, boolean send) { 348 349 try { 350 String hdr; 351 OutputStream os; 352 InputStream is; 353 int b; 354 355 if (name.endsWith("/")) { 356 name = name + server.getDefaultWebPage(); 357 } 358 359 if (name.indexOf("..") != -1) { 361 processError(HttpURLConnection.HTTP_FORBIDDEN); 362 363 return; 364 } 365 366 name = server.getWebRoot() + name; 367 368 if (File.separatorChar != '/') { 369 name = name.replace('/', File.separatorChar); 370 } 371 372 is = null; 373 374 server.printWithThread("GET " + name); 375 376 try { 377 File file = new File (name); 378 379 is = new DataInputStream (new FileInputStream (file)); 380 hdr = getHead(HEADER_OK, true, getMimeTypeString(name), 381 (int) file.length()); 382 } catch (IOException e) { 383 processError(HttpURLConnection.HTTP_NOT_FOUND); 384 385 if (is != null) { 386 is.close(); 387 } 388 389 return; 390 } 391 392 os = new BufferedOutputStream (socket.getOutputStream()); 393 394 os.write(hdr.getBytes(ENCODING)); 395 396 if (send) { 397 while ((b = is.read()) != -1) { 398 os.write(b); 399 } 400 } 401 402 os.flush(); 403 os.close(); 404 is.close(); 405 } catch (Exception e) { 406 server.printError("processGet: " + e.toString()); 407 server.printStackTrace(e); 408 } 409 } 410 411 420 String getHead(String responseCodeString, boolean addInfo, 421 String mimeType, int length) { 422 423 StringBuffer sb = new StringBuffer (128); 424 425 sb.append(responseCodeString).append("\r\n"); 426 427 if (addInfo) { 428 sb.append("Allow: GET, HEAD, POST\nMIME-Version: 1.0\r\n"); 429 sb.append("Server: ").append( 430 HsqlDatabaseProperties.PRODUCT_NAME).append("\r\n"); 431 } 432 433 if (mimeType != null) { 434 sb.append("Content-Type: ").append(mimeType).append("\r\n"); 435 sb.append("Content-Length: ").append(length).append("\r\n"); 436 } 437 438 sb.append("\r\n"); 439 440 return sb.toString(); 441 } 442 443 449 private void processError(int code) { 450 451 String msg; 452 453 server.printWithThread("processError " + code); 454 455 switch (code) { 456 457 case HttpURLConnection.HTTP_BAD_REQUEST : 458 msg = getHead(HEADER_BAD_REQUEST, false, null, 0); 459 msg += BundleHandler.getString(WebServer.webBundleHandle, 460 "BAD_REQUEST"); 461 break; 462 463 case HttpURLConnection.HTTP_FORBIDDEN : 464 msg = getHead(HEADER_FORBIDDEN, false, null, 0); 465 msg += BundleHandler.getString(WebServer.webBundleHandle, 466 "FORBIDDEN"); 467 break; 468 469 case HttpURLConnection.HTTP_NOT_FOUND : 470 default : 471 msg = getHead(HEADER_NOT_FOUND, false, null, 0); 472 msg += BundleHandler.getString(WebServer.webBundleHandle, 473 "NOT_FOUND"); 474 break; 475 } 476 477 try { 478 OutputStream os = 479 new BufferedOutputStream (socket.getOutputStream()); 480 481 os.write(msg.getBytes(ENCODING)); 482 os.flush(); 483 os.close(); 484 } catch (Exception e) { 485 server.printError("processError: " + e.toString()); 486 server.printStackTrace(e); 487 } 488 } 489 490 497 String getConnectionThreadName() { 498 return "HSQLDB HTTP Connection @" + Integer.toString(hashCode(), 16); 499 } 500 } 501 | Popular Tags |