1 29 30 package com.caucho.quercus.lib; 31 32 import com.caucho.quercus.annotation.Optional; 33 import com.caucho.quercus.env.*; 34 import com.caucho.quercus.module.AbstractQuercusModule; 35 import com.caucho.quercus.module.ModuleStartupListener; 36 import com.caucho.util.L10N; 37 import com.caucho.vfs.StreamImplOutputStream; 38 import com.caucho.vfs.TempStream; 39 40 import java.io.IOException ; 41 import java.io.OutputStream ; 42 import java.util.HashMap ; 43 import java.util.Map ; 44 import java.util.logging.Logger ; 45 import java.util.zip.DeflaterOutputStream ; 46 import java.util.zip.GZIPOutputStream ; 47 48 51 public class OutputModule extends AbstractQuercusModule 52 implements ModuleStartupListener { 53 private static final L10N L = new L10N(OutputModule.class); 54 private static final Logger log 55 = Logger.getLogger(OutputModule.class.getName()); 56 private static final StringValue HTTP_ACCEPT_ENCODING 57 = new StringValueImpl("HTTP_ACCEPT_ENCODING"); 58 59 private static final HashMap <String ,StringValue> _iniMap 60 = new HashMap <String ,StringValue>(); 61 62 private enum Encoding {NONE, GZIP, DEFLATE}; 64 65 private static class GZOutputPair { 66 public TempStream tempStream; 67 public OutputStream outputStream; 68 } 69 70 private static HashMap <Env,GZOutputPair> _gzOutputPairs 71 = new HashMap <Env,GZOutputPair>(); 72 73 74 77 public Map <String ,StringValue> getDefaultIni() 78 { 79 return _iniMap; 80 } 81 82 public void startup(Env env) 83 { 84 String handlerName = env.getConfigVar("output_handler").toString(); 85 86 if (! "".equals(handlerName) && env.getFunction(handlerName) != null) { 87 Callback callback = env.createCallback(new StringValueImpl(handlerName)); 88 89 ob_start(env, callback, 0, true); 90 } else if (env.getConfigVar("output_buffering").toBoolean()) { 91 ob_start(env, null, 0, true); 92 } 93 94 ob_implicit_flush(env, env.getConfigVar("output_buffering").toBoolean()); 95 } 96 97 100 public Value flush(Env env) 101 { 102 try { 103 env.getOriginalOut().flushBuffer(); 105 } catch (IOException e) { 106 } 107 108 return NullValue.NULL; 109 } 110 111 114 public static Value ob_clean(Env env) 115 { 116 OutputBuffer ob = env.getOutputBuffer(); 117 118 if (ob != null) { 119 ob.clean(); 120 121 return BooleanValue.TRUE; 122 } 123 else 124 return BooleanValue.FALSE; 125 } 126 127 130 public static boolean ob_end_clean(Env env) 131 { 132 OutputBuffer ob = env.getOutputBuffer(); 133 134 if (ob != null) { 135 ob.clean(); 136 137 Callback callback = ob.getCallback(); 138 139 if (callback != null) { 140 if (callback.getCallbackName().equals("ob_gzhandler")) 141 _gzOutputPairs.remove(env); 142 143 ob.setCallback(null); 144 } 145 } 146 147 return env.popOutputBuffer(); 148 } 149 150 153 public static boolean ob_end_flush(Env env) 154 { 155 return env.popOutputBuffer(); 156 } 157 158 161 public static Value ob_get_clean(Env env) 162 { 163 OutputBuffer ob = env.getOutputBuffer(); 164 165 if (ob != null) { 166 Value result = ob.getContents(); 167 168 ob.clean(); 169 170 return result; 171 } 172 else 173 return BooleanValue.FALSE; 174 } 175 176 179 public static Value ob_get_contents(Env env) 180 { 181 OutputBuffer ob = env.getOutputBuffer(); 182 183 if (ob != null) 184 return ob.getContents(); 185 else 186 return BooleanValue.FALSE; 187 } 188 189 192 public static Value ob_get_flush(Env env) 193 { 194 OutputBuffer ob = env.getOutputBuffer(); 195 196 Value result = BooleanValue.FALSE; 197 if (ob != null) { 198 result = ob.getContents(); 199 } 200 201 env.popOutputBuffer(); 202 203 return result; 204 } 205 206 212 public static Value ob_flush(Env env) 213 { 214 OutputBuffer ob = env.getOutputBuffer(); 215 216 if (ob != null) { 217 ob.flush(); 218 219 return BooleanValue.TRUE; 220 } 221 else 222 return BooleanValue.FALSE; 223 } 224 225 228 public static Value ob_get_length(Env env) 229 { 230 OutputBuffer ob = env.getOutputBuffer(); 231 232 if (ob != null) 233 return LongValue.create(ob.getLength()); 234 else 235 return BooleanValue.FALSE; 236 } 237 238 241 public static Value ob_get_level(Env env) 242 { 243 OutputBuffer ob = env.getOutputBuffer(); 244 245 if (ob != null) 246 return LongValue.create(ob.getLevel()); 247 else 248 return LongValue.ZERO; 249 } 250 251 255 private static void listHandlers(OutputBuffer ob, ArrayValue handlers) 256 { 257 if (ob == null) 258 return; 259 260 listHandlers(ob.getNext(), handlers); 261 262 Callback callback = ob.getCallback(); 263 264 if (callback != null) 265 handlers.put(new StringValueImpl(callback.getCallbackName())); 266 else 267 handlers.put(new StringValueImpl("default output handler")); 268 } 269 270 273 public static Value ob_list_handlers(Env env) 274 { 275 OutputBuffer ob = env.getOutputBuffer(); 276 ArrayValue handlers = new ArrayValueImpl(); 277 278 listHandlers(ob, handlers); 279 280 return handlers; 281 } 282 283 287 private static void putCommonStatus(ArrayValue element, OutputBuffer ob, 288 Env env, boolean fullStatus) 289 { 290 LongValue type = LongValue.ONE; 291 Callback callback = ob.getCallback(); 292 293 if (callback != null && callback.isInternal()) 294 type = LongValue.ZERO; 295 296 element.put(new StringValueImpl("type"), type); 297 298 if (fullStatus && callback != null && 304 callback == UrlRewriterCallback.getInstance(env)) 305 element.put(new StringValueImpl("buffer_size"), LongValue.ZERO); 306 307 LongValue status = ob.haveFlushed() ? LongValue.ONE : LongValue.ZERO; 317 element.put(new StringValueImpl("status"), status); 318 319 StringValue name; 320 321 if (callback != null) 322 name = new StringValueImpl(callback.getCallbackName()); 323 else 324 name = new StringValueImpl("default output handler".intern()); 325 326 element.put(new StringValueImpl("name".intern()), name); 327 328 Value del = ob.getEraseFlag() ? BooleanValue.TRUE : 329 BooleanValue.FALSE; 330 element.put(new StringValueImpl("del"), del); 331 } 332 333 337 private static void getFullStatus(OutputBuffer ob, Env env, ArrayValue result) 338 { 339 if (ob == null) 340 return; 341 342 getFullStatus(ob.getNext(), env, result); 343 344 ArrayValue element = new ArrayValueImpl(); 345 346 element.put(new StringValueImpl("chunk_size"), 347 LongValue.create(ob.getChunkSize())); 348 349 element.put(new StringValueImpl("size"), LongValue.create(-1)); 353 element.put(new StringValueImpl("block_size"), LongValue.create(-1)); 354 355 putCommonStatus(element, ob, env, true); 356 357 result.put(element); 358 } 359 360 363 public static Value ob_get_status(Env env, @Optional boolean full_status) 364 { 365 if (full_status) { 366 OutputBuffer ob = env.getOutputBuffer(); 367 ArrayValue result = new ArrayValueImpl(); 368 369 getFullStatus(ob, env, result); 370 371 return result; 372 } 373 374 OutputBuffer ob = env.getOutputBuffer(); 375 ArrayValue result = new ArrayValueImpl(); 376 377 if (ob != null) { 378 result.put(new StringValueImpl("level"), 379 LongValue.create(ob.getLevel())); 380 381 putCommonStatus(result, ob, env, false); 382 } 383 384 return result; 386 } 387 388 391 public static Value ob_implicit_flush(Env env, @Optional("true") boolean flag) 392 { 393 if (env.getOriginalOut() != null) 394 env.getOriginalOut().setImplicitFlush(flag); 395 396 return NullValue.NULL; 397 } 398 399 402 public static boolean ob_start(Env env, 403 @Optional Callback callback, 404 @Optional int chunkSize, 405 @Optional("true") boolean erase) 406 { 407 if (callback != null && callback.getCallbackName().equals("ob_gzhandler")) { 408 OutputBuffer ob = env.getOutputBuffer(); 409 410 for (; ob != null; ob = ob.getNext()) { 411 Callback cb = ob.getCallback(); 412 413 if (cb.getCallbackName().equals("ob_gzhandler")) { 414 env.warning(L.l("output handler 'ob_gzhandler' cannot be used twice")); 415 return false; 416 } 417 } 418 } 419 420 env.pushOutputBuffer(callback, chunkSize, erase); 421 422 return true; 423 } 424 425 429 public static UrlRewriterCallback pushUrlRewriter(Env env) 430 { 431 UrlRewriterCallback rewriter = UrlRewriterCallback.getInstance(env); 432 433 if (rewriter == null) { 434 OutputBuffer ob = env.getOutputBuffer(); 435 rewriter = new UrlRewriterCallback(env); 436 437 if (ob != null && ob.getCallback() == null) 440 ob.setCallback(rewriter); 441 else 442 ob_start(env, rewriter, 0, true); 443 } 444 445 return rewriter; 446 } 447 448 451 public static boolean output_add_rewrite_var(Env env, 452 String name, String value) 453 { 454 UrlRewriterCallback rewriter = pushUrlRewriter(env); 455 456 rewriter.addRewriterVar(name, value); 457 458 return true; 459 } 460 461 464 public static boolean output_reset_rewrite_vars(Env env) 465 { 466 UrlRewriterCallback rewriter = UrlRewriterCallback.getInstance(env); 467 468 rewriter.resetRewriterVars(); 469 470 return true; 471 } 472 473 481 public static Value ob_gzhandler(Env env, StringValue buffer, int state) 482 { 483 Encoding encoding = Encoding.NONE; 484 Value _SERVER = env.getSpecialRef("_SERVER"); 485 486 String [] acceptedList = 487 _SERVER.get(HTTP_ACCEPT_ENCODING).toString().split(","); 488 489 for (String accepted : acceptedList) { 490 accepted = accepted.trim(); 491 492 if (accepted.equalsIgnoreCase("gzip")) { 493 encoding = Encoding.GZIP; 494 break; 495 } else if (accepted.equalsIgnoreCase("deflate")) { 496 encoding = Encoding.DEFLATE; 497 break; 498 } 499 } 500 501 if (encoding == Encoding.NONE) 502 return NullValue.NULL; 503 504 GZOutputPair pair = null; 505 506 if ((state & (1 << OutputBuffer.PHP_OUTPUT_HANDLER_START)) != 0) { 507 HttpModule.header(env, "Vary: Accept-Encoding", true, 0); 508 509 int encodingFlag = 0; 510 511 pair = new GZOutputPair(); 512 pair.tempStream = new TempStream(); 513 StreamImplOutputStream siout = 514 new StreamImplOutputStream(pair.tempStream); 515 516 try { 517 if (encoding == Encoding.GZIP) { 518 HttpModule.header(env, "Content-Encoding: gzip", true, 0); 519 520 pair.outputStream = new GZIPOutputStream (siout); 521 } else if (encoding == Encoding.DEFLATE) { 522 HttpModule.header(env, "Content-Encoding: deflate", true, 0); 523 524 pair.outputStream = new DeflaterOutputStream (siout); 525 } 526 } catch (IOException e) { 527 return NullValue.NULL; 528 } 529 530 _gzOutputPairs.put(env, pair); 531 } else { 532 pair = _gzOutputPairs.get(env); 533 534 if (pair == null) 535 return NullValue.NULL; 536 } 537 538 try { 539 pair.outputStream.write(buffer.toString().getBytes()); 540 pair.outputStream.flush(); 541 542 if ((state & (1 << OutputBuffer.PHP_OUTPUT_HANDLER_END)) != 0) { 543 pair.outputStream.close(); 544 545 _gzOutputPairs.remove(env); 546 } 547 548 } catch (IOException e) { 549 return NullValue.NULL; 550 } 551 552 Value result = new TempBufferStringValue(pair.tempStream.getHead()); 553 554 pair.tempStream.discard(); 555 556 return result; 557 } 558 559 static { 560 addIni(_iniMap, "output_buffering", "0", PHP_INI_PERDIR); 561 addIni(_iniMap, "output_handler", "", PHP_INI_PERDIR); 562 addIni(_iniMap, "implicit_flush", "0", PHP_INI_ALL); 563 } 564 } 565 | Popular Tags |