PKd9org/PKd9 org/jruby/PKd9org/jruby/rack/PKd9org/jruby/webapp/PKd9D2MH-org/jruby/rack/DefaultRackApplication$1.classH1N , - ./ 01 23 45 67 89:;<val$envLjavax/servlet/ServletRequest;this$0'Lorg/jruby/rack/DefaultRackApplication;H(Lorg/jruby/rack/DefaultRackApplication;Ljavax/servlet/ServletRequest;)VCodeLineNumberTableLocalVariableTablethis InnerClasses)Lorg/jruby/rack/DefaultRackApplication$1;execute(Lorg/jruby/runtime/builtin/IRubyObject;[Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/Block;)Lorg/jruby/runtime/builtin/IRubyObject;exLjava/io/IOException;recv'Lorg/jruby/runtime/builtin/IRubyObject;args([Lorg/jruby/runtime/builtin/IRubyObject;blockLorg/jruby/runtime/Block;getArity()Lorg/jruby/runtime/Arity; SourceFileDefaultRackApplication.javaEnclosingMethod= >?   @org/jruby/RubyIOA BCD EF Gjava/io/IOExceptionH IJK LM'org/jruby/rack/DefaultRackApplication$1java/lang/Object#org/jruby/runtime/callback/Callback%org/jruby/rack/DefaultRackApplicationcall=(Ljavax/servlet/ServletRequest;)Lorg/jruby/rack/RackResponse;()V%org/jruby/runtime/builtin/IRubyObject getRuntime()Lorg/jruby/Ruby;javax/servlet/ServletRequestgetInputStream$()Ljavax/servlet/ServletInputStream;((Lorg/jruby/Ruby;Ljava/io/InputStream;)V#org/jruby/exceptions/RaiseExceptioncreateNativeRaiseExceptionL(Lorg/jruby/Ruby;Ljava/lang/Throwable;)Lorg/jruby/exceptions/RaiseException;org/jruby/runtime/Arity NO_ARGUMENTSLorg/jruby/runtime/Arity;  9*+*,*( %Y+*:+ #$%4 %% %!"%#$%&. ) '()*+  PKd9% l g +org/jruby/rack/DefaultRackApplication.classg 1^ 4 56 7 8 59 :;<= @ AB CD 5E F :8 GHIJK application'Lorg/jruby/runtime/builtin/IRubyObject;adapterLorg/jruby/RubyObjectAdapter;()VCodeLineNumberTableLocalVariableTablethis'Lorg/jruby/rack/DefaultRackApplication;call=(Ljavax/servlet/ServletRequest;)Lorg/jruby/rack/RackResponse;envLjavax/servlet/ServletRequest;runtimeLorg/jruby/Ruby; servlet_envresponseinit ExceptionsLdestroy getRuntime()Lorg/jruby/Ruby;setApplication*(Lorg/jruby/runtime/builtin/IRubyObject;)V__callP(Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject; SourceFileDefaultRackApplication.java M NO  ,- PQR STto_io'org/jruby/rack/DefaultRackApplication$1 InnerClasses UV WX 01org/jruby/rack/RackResponse YZ [ \]%org/jruby/rack/DefaultRackApplicationjava/lang/Objectorg/jruby/rack/RackApplication*org/jruby/rack/RackInitializationException$org/jruby/javasupport/JavaEmbedUtilsnewObjectAdapter()Lorg/jruby/RubyObjectAdapter; javaToRubyK(Lorg/jruby/Ruby;Ljava/lang/Object;)Lorg/jruby/runtime/builtin/IRubyObject;%org/jruby/runtime/builtin/IRubyObject getMetaClass()Lorg/jruby/RubyClass;H(Lorg/jruby/rack/DefaultRackApplication;Ljavax/servlet/ServletRequest;)Vorg/jruby/RubyClass defineMethod:(Ljava/lang/String;Lorg/jruby/runtime/callback/Callback;)V rubyToJava\(Lorg/jruby/Ruby;Lorg/jruby/runtime/builtin/IRubyObject;Ljava/lang/Class;)Ljava/lang/Object;org/jruby/RubyObjectAdapter callMethod(Lorg/jruby/runtime/builtin/IRubyObject;Ljava/lang/String;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;!: **    !3*M,+N-Y*+ *- :,  ,&-433"#.$% (&& '(+1 )*++4 ,-4 *7  ./>*+ ;<01E**+@"23? PKd94org/jruby/rack/DefaultRackApplicationFactory$1.class41'    this$0.Lorg/jruby/rack/DefaultRackApplicationFactory;1(Lorg/jruby/rack/DefaultRackApplicationFactory;)VCodeLineNumberTableLocalVariableTablethis InnerClasses0Lorg/jruby/rack/DefaultRackApplicationFactory$1;create9(Lorg/jruby/Ruby;)Lorg/jruby/runtime/builtin/IRubyObject;runtimeLorg/jruby/Ruby; SourceFile"DefaultRackApplicationFactory.javaEnclosingMethod" #$  % &.org/jruby/rack/DefaultRackApplicationFactory$1java/lang/ObjectEorg/jruby/rack/DefaultRackApplicationFactory$ApplicationObjectFactoryApplicationObjectFactory,org/jruby/rack/DefaultRackApplicationFactorynewApplication"()Lorg/jruby/rack/RackApplication;()VcreateApplicationObject   4 *+* -   = *+ .   ! PKd94org/jruby/rack/DefaultRackApplicationFactory$2.class*1'    this$0.Lorg/jruby/rack/DefaultRackApplicationFactory;1(Lorg/jruby/rack/DefaultRackApplicationFactory;)VCodeLineNumberTableLocalVariableTablethis InnerClasses0Lorg/jruby/rack/DefaultRackApplicationFactory$2;create9(Lorg/jruby/Ruby;)Lorg/jruby/runtime/builtin/IRubyObject;runtimeLorg/jruby/Ruby; SourceFile"DefaultRackApplicationFactory.javaEnclosingMethod" #$  % &.org/jruby/rack/DefaultRackApplicationFactory$2java/lang/ObjectEorg/jruby/rack/DefaultRackApplicationFactory$ApplicationObjectFactoryApplicationObjectFactory,org/jruby/rack/DefaultRackApplicationFactorynewErrorApplication"()Lorg/jruby/rack/RackApplication;()VcreateErrorApplicationObject   4 *+* e   = *+ f   ! PKd9;L#6org/jruby/rack/DefaultRackApplicationFactory$3$1.class`1O - . /01 .2 3 4 56 7 89:;<=this$1> InnerClasses0Lorg/jruby/rack/DefaultRackApplicationFactory$3;3(Lorg/jruby/rack/DefaultRackApplicationFactory$3;)VCodeLineNumberTableLocalVariableTablethis2Lorg/jruby/rack/DefaultRackApplicationFactory$3$1; getStatus()I getHeaders()Ljava/util/Map;getBody()Ljava/lang/String;respond+(Ljavax/servlet/http/HttpServletResponse;)VexLjava/io/IOException;response(Ljavax/servlet/http/HttpServletResponse; SourceFile"DefaultRackApplicationFactory.javaEnclosingMethod ?@  AB CDjava/lang/StringBuilder#Application initialization failed: EF GHI J" K"L MNjava/io/IOException0org/jruby/rack/DefaultRackApplicationFactory$3$1java/lang/Objectorg/jruby/rack/RackResponse.org/jruby/rack/DefaultRackApplicationFactory$3call=(Ljavax/servlet/ServletRequest;)Lorg/jruby/rack/RackResponse;()Vjava/util/Collections EMPTY_MAPLjava/util/Map;append-(Ljava/lang/String;)Ljava/lang/StringBuilder;val$eLjava/lang/Exception;java/lang/Exception getMessagetoString&javax/servlet/http/HttpServletResponse sendError(ILjava/lang/String;)V 4 *+*u  .r  .s !"-t #$x*+Y*  M%( w%z){ )%&**'()*+,PKd94org/jruby/rack/DefaultRackApplicationFactory$3.class71: ) * +, -./ 0123val$eLjava/lang/Exception;this$0.Lorg/jruby/rack/DefaultRackApplicationFactory;F(Lorg/jruby/rack/DefaultRackApplicationFactory;Ljava/lang/Exception;)VCodeLineNumberTableLocalVariableTablethis InnerClasses0Lorg/jruby/rack/DefaultRackApplicationFactory$3;init()V Exceptions4call=(Ljavax/servlet/ServletRequest;)Lorg/jruby/rack/RackResponse;envLjavax/servlet/ServletRequest;destroy getRuntime()Lorg/jruby/Ruby; SourceFile"DefaultRackApplicationFactory.javaEnclosingMethod5 67  0org/jruby/rack/DefaultRackApplicationFactory$3$1 8'java/lang/UnsupportedOperationException not supported 9.org/jruby/rack/DefaultRackApplicationFactory$3java/lang/Objectorg/jruby/rack/RackApplication*org/jruby/rack/RackInitializationException,org/jruby/rack/DefaultRackApplicationFactorynewErrorApplication"()Lorg/jruby/rack/RackApplication;3(Lorg/jruby/rack/DefaultRackApplicationFactory$3;)V(Ljava/lang/String;)V   9*+*,* +o = Y*q   !+~ "#4 Y  $%&'( PKd94org/jruby/rack/DefaultRackApplicationFactory$4.class1B ) * + , - ./0 1 2345 val$appfact6ApplicationObjectFactory InnerClassesGLorg/jruby/rack/DefaultRackApplicationFactory$ApplicationObjectFactory; val$runtimeLorg/jruby/Ruby;this$0.Lorg/jruby/rack/DefaultRackApplicationFactory;(Lorg/jruby/rack/DefaultRackApplicationFactory;Lorg/jruby/rack/DefaultRackApplicationFactory$ApplicationObjectFactory;Lorg/jruby/Ruby;)VCodeLineNumberTableLocalVariableTablethis0Lorg/jruby/rack/DefaultRackApplicationFactory$4; Exceptionsinit()Vre%Lorg/jruby/exceptions/RaiseException;destroy SourceFile"DefaultRackApplicationFactory.javaEnclosingMethod7 89     :; <=#org/jruby/exceptions/RaiseException*org/jruby/rack/RackInitializationException >? @A.org/jruby/rack/DefaultRackApplicationFactory$4%org/jruby/rack/DefaultRackApplicationEorg/jruby/rack/DefaultRackApplicationFactory$ApplicationObjectFactory,org/jruby/rack/DefaultRackApplicationFactorycreateApplicationi(Lorg/jruby/rack/DefaultRackApplicationFactory$ApplicationObjectFactory;)Lorg/jruby/rack/RackApplication;create9(Lorg/jruby/Ruby;)Lorg/jruby/runtime/builtin/IRubyObject;setApplication*(Lorg/jruby/runtime/builtin/IRubyObject;)V((Lorg/jruby/exceptions/RaiseException;)V$org/jruby/javasupport/JavaEmbedUtils terminate(Lorg/jruby/Ruby;)V  >*+*,*-*  k*** LY+  !"# 6*   $%&'(' PKd9~qlKorg/jruby/rack/DefaultRackApplicationFactory$ApplicationObjectFactory.classl1  create9(Lorg/jruby/Ruby;)Lorg/jruby/runtime/builtin/IRubyObject; SourceFile"DefaultRackApplicationFactory.java Eorg/jruby/rack/DefaultRackApplicationFactory$ApplicationObjectFactoryApplicationObjectFactory InnerClassesjava/lang/Object,org/jruby/rack/DefaultRackApplicationFactory   PKd9X2org/jruby/rack/DefaultRackApplicationFactory.class1 =z <{m |} <~   < < < < <  z   z    ' < + | / 1z 1 1 < 8 = ApplicationObjectFactory InnerClasses rackupScriptLjava/lang/String;servletContextLjavax/servlet/ServletContext; classCacheLorg/jruby/util/ClassCache;errorApplication Lorg/jruby/rack/RackApplication;()VCodeLineNumberTableLocalVariableTablethis.Lorg/jruby/rack/DefaultRackApplicationFactory;init!(Ljavax/servlet/ServletContext;)VnewApplication"()Lorg/jruby/rack/RackApplication; ExceptionsgetApplicationappfinishedWithApplication#(Lorg/jruby/rack/RackApplication;)VgetErrorApplicationdestroy newRuntime()Lorg/jruby/Ruby;binjrubyeLjava/lang/Exception;configLorg/jruby/RubyInstanceConfig;runtimeLorg/jruby/Ruby;re%Lorg/jruby/exceptions/RaiseException;createApplicationObject9(Lorg/jruby/Ruby;)Lorg/jruby/runtime/builtin/IRubyObject;createErrorApplicationObjectnewErrorApplicationcreateRackServletWrapperK(Lorg/jruby/Ruby;Ljava/lang/String;)Lorg/jruby/runtime/builtin/IRubyObject;rackupcreateApplicationi(Lorg/jruby/rack/DefaultRackApplicationFactory$ApplicationObjectFactory;)Lorg/jruby/rack/RackApplication;rie,Lorg/jruby/rack/RackInitializationException;appfactGLorg/jruby/rack/DefaultRackApplicationFactory$ApplicationObjectFactory;verify6(Lorg/jruby/Ruby;Ljava/lang/String;)Ljava/lang/String;scriptsetErrorApplication SourceFile"DefaultRackApplicationFactory.java JK DE BC  FG HI jT.org/jruby/rack/DefaultRackApplicationFactory$1 J no ST QK [Korg/jruby/RubyInstanceConfig /META-INF/jruby.home/bin/jruby    java/lang/Exceptionjava/util/ArrayList  $servlet_context  require 'rack/handler/servlet' #org/jruby/exceptions/RaiseException*org/jruby/rack/RackInitializationException J klrun JRuby::Rack::ErrorsApp.new.org/jruby/rack/DefaultRackApplicationFactory$23Warning: error application could not be initialized .org/jruby/rack/DefaultRackApplicationFactory$3 Jjava/lang/StringBuilderload 'jruby/rack/boot/rack.rb' JRuby::Rack::Bootstrap.instance.change_to_root_directory Rack::Handler::Servlet.new(Rack::Builder.new {(  )}.to_app) \].org/jruby/rack/DefaultRackApplicationFactory$4 J ,org/jruby/rack/DefaultRackApplicationFactoryjava/lang/Object%org/jruby/rack/RackApplicationFactoryEorg/jruby/rack/DefaultRackApplicationFactory$ApplicationObjectFactoryjavax/servlet/ServletContextgetInitParameter&(Ljava/lang/String;)Ljava/lang/String;java/lang/Thread currentThread()Ljava/lang/Thread;getContextClassLoader()Ljava/lang/ClassLoader;$org/jruby/javasupport/JavaEmbedUtilscreateClassCache4(Ljava/lang/ClassLoader;)Lorg/jruby/util/ClassCache;1(Lorg/jruby/rack/DefaultRackApplicationFactory;)Vorg/jruby/rack/RackApplication setClassCache(Lorg/jruby/util/ClassCache;)Vjava/lang/Class getResource"(Ljava/lang/String;)Ljava/net/URL; java/net/URLtoURI()Ljava/net/URI; java/net/URIgetSchemeSpecificPart()Ljava/lang/String;java/lang/Stringlength()I substring(II)Ljava/lang/String; setJRubyHome(Ljava/lang/String;)V initialize@(Ljava/util/List;Lorg/jruby/RubyInstanceConfig;)Lorg/jruby/Ruby;org/jruby/RubygetGlobalVariables.()Lorg/jruby/internal/runtime/GlobalVariables; javaToRubyK(Lorg/jruby/Ruby;Ljava/lang/Object;)Lorg/jruby/runtime/builtin/IRubyObject;*org/jruby/internal/runtime/GlobalVariablessetb(Ljava/lang/String;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject; evalScriptlet;(Ljava/lang/String;)Lorg/jruby/runtime/builtin/IRubyObject;((Lorg/jruby/exceptions/RaiseException;)Vlog*(Ljava/lang/String;Ljava/lang/Throwable;)VF(Lorg/jruby/rack/DefaultRackApplicationFactory;Ljava/lang/Exception;)Vappend-(Ljava/lang/String;)Ljava/lang/StringBuilder;toString(Lorg/jruby/rack/DefaultRackApplicationFactory;Lorg/jruby/rack/DefaultRackApplicationFactory$ApplicationObjectFactory;Lorg/jruby/Ruby;)V getMessage!<=>BCDEFGHIJKL3*M N OPQRLv.*+*+* * ** M"#$&%'-)N.OP.DESTL7 * Y* M,N  OPU'VTLI *L++M45 6N OPWIU'XYL?+M :;NOPWIZTL/* M>N OP[KLA* * MB CDN OP\]LdYL+* M+,, dMY+M, !,*"#W,$%W,L'Y+(/2YZ&M. HIKM/N3O?PQRXSZT[UN>^C3_`Rab?cd[ efdOPU'ghL> *+*)MZN OP cdihL<*+*)M^NOPcdjTL,*+Y*,L++L*-+./Y*+0Mc ijkl"nN  WI_`,OPklL[+1Y234,4546%MN OPcdmCnoL*7M8Y*+,9M,M'Y,('&MN4 cdpq efOPrsU'tuLg+,%:N-; M N* _`OPcdvCwYL>*+ M NOPWIxyA*?<@ +/8PKd96l *org/jruby/rack/DefaultRackDispatcher.class 1t : ; < = >? @A BC DE FGH IJK FL IM NO PQRS ITUVWservletContextLjavax/servlet/ServletContext;!(Ljavax/servlet/ServletContext;)VCodeLineNumberTableLocalVariableTablethis&Lorg/jruby/rack/DefaultRackDispatcher;processR(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)VreLjava/lang/Exception;request'Ljavax/servlet/http/HttpServletRequest;response(Ljavax/servlet/http/HttpServletResponse; rackFactory'Lorg/jruby/rack/RackApplicationFactory;app Lorg/jruby/rack/RackApplication; ExceptionsXYgetRackFactory)()Lorg/jruby/rack/RackApplicationFactory;handleException(Ljava/lang/Exception;Lorg/jruby/rack/RackApplicationFactory;Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)VerrorAppe SourceFileDefaultRackDispatcher.java Z  23 [\] ^_` ab cdjava/lang/Exception 45 rack.factorye fg%org/jruby/rack/RackApplicationFactoryh ij0Error: Couldn't handle error: response committed kl mZ n\rack.exceptiono pqException caughtError: Couldn't handle error rs$org/jruby/rack/DefaultRackDispatcherjava/lang/Objectorg/jruby/rack/RackDispatcherjavax/servlet/ServletExceptionjava/io/IOException()VgetApplication"()Lorg/jruby/rack/RackApplication;org/jruby/rack/RackApplicationcall=(Ljavax/servlet/ServletRequest;)Lorg/jruby/rack/RackResponse;org/jruby/rack/RackResponserespond+(Ljavax/servlet/http/HttpServletResponse;)VfinishedWithApplication#(Lorg/jruby/rack/RackApplication;)Vjavax/servlet/ServletContext getAttribute&(Ljava/lang/String;)Ljava/lang/Object;&javax/servlet/http/HttpServletResponse isCommitted()Zlog*(Ljava/lang/String;Ljava/lang/Throwable;)VresetgetErrorApplication%javax/servlet/http/HttpServletRequest setAttribute'(Ljava/lang/String;Ljava/lang/Object;)V sendError(I)V!F **+   !" #$\*N:-:+,;-0:*-+,  -: -.I.9IIKI6  $#%.!0"9$>%I$P%[( >0 %&\!"\'(\)*W+,T-./01239*  + !"45g *+,:-+*+-:*JM6 2 3469&:/;;<J@M=O>\?fA H&$6.O7&g!"g%&g+,g'(g)*/0189PKd9org/jruby/rack/merb/PKd9X5#4org/jruby/rack/PoolingRackApplicationFactory$1.class1g 2 3 4 56 578 9 0: 5; 0<= 4> ? 5@ A B CD EFG CHIJKval$appsLjava/util/Queue;this$0.Lorg/jruby/rack/PoolingRackApplicationFactory;B(Lorg/jruby/rack/PoolingRackApplicationFactory;Ljava/util/Queue;)VCodeLineNumberTableLocalVariableTablethis InnerClasses0Lorg/jruby/rack/PoolingRackApplicationFactory$1;run()Vapp Lorg/jruby/rack/RackApplication;ex,Lorg/jruby/rack/RackInitializationException; SourceFile"PoolingRackApplicationFactory.javaEnclosingMethodL MN   (O PQ RSorg/jruby/rack/RackApplication T( UV WX YZjava/lang/StringBuilder.Info: add application to the pool. size now = [\ ]^ [_ `ab cd e(*org/jruby/rack/RackInitializationException'Error: unable to initialize application cf.org/jruby/rack/PoolingRackApplicationFactory$1java/lang/Objectjava/lang/Runnable,org/jruby/rack/PoolingRackApplicationFactorylaunchInitializerThreads(Ljava/util/Queue;)Vjava/util/QueueisEmpty()Zremove()Ljava/lang/Object;init access$000A(Lorg/jruby/rack/PoolingRackApplicationFactory;)Ljava/util/Queue;add(Ljava/lang/Object;)Z access$100N(Lorg/jruby/rack/PoolingRackApplicationFactory;)Ljavax/servlet/ServletContext;append-(Ljava/lang/String;)Ljava/lang/StringBuilder;size()I(I)Ljava/lang/StringBuilder;toString()Ljava/lang/String;javax/servlet/ServletContextlog(Ljava/lang/String;)V notifyAll*(Ljava/lang/String;Ljava/lang/Throwable;)V  9*+*,*!" #&'( TL*YM*,ç{*L,çN,-+*YM*+ W* Y  **,ç :,qL* + ,),,/,A!F '17AOy" )*+,#&-./01% PKd9m+2org/jruby/rack/PoolingRackApplicationFactory.classn18 X X Y  X X Z X U     X X X X U  X X X  #  Z  Z ( X Xu0 X U ;  : : Z B Y X  U UDEFAULT_TIMEOUTI ConstantValueservletContextLjavax/servlet/ServletContext; realFactory'Lorg/jruby/rack/RackApplicationFactory;applicationPoolLjava/util/Queue; Signature3Ljava/util/Queue;initialLjava/lang/Integer;maximumtimeoutJpermits Ljava/util/concurrent/Semaphore;*(Lorg/jruby/rack/RackApplicationFactory;)VCodeLineNumberTableLocalVariableTablethis.Lorg/jruby/rack/PoolingRackApplicationFactory;factoryinit!(Ljavax/servlet/ServletContext;)VspecifiedTimeout ExceptionsnewApplication"()Lorg/jruby/rack/RackApplication;getApplicationex Ljava/lang/InterruptedException;finishedWithApplication#(Lorg/jruby/rack/RackApplication;)Vapp Lorg/jruby/rack/RackApplication;getErrorApplicationdestroy()Vi$Ljava/util/Iterator;getApplicationPool()Ljava/util/Collection;:()Ljava/util/Collection;fillInitialPoolappsLocalVariableTypeTablelaunchInitializerThreads(Ljava/util/Queue;)Vi numThreads6(Ljava/util/Queue;)VcreateApplications()Ljava/util/Queue;,Lorg/jruby/rack/RackInitializationException;5()Ljava/util/Queue;waitForNextAvailable(J)V getInitial()Ljava/lang/Integer; getMaximum getRangeValue9(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Integer;endLjava/lang/String;gsValuevgetPositiveInteger'(Ljava/lang/String;)Ljava/lang/Integer;eLjava/lang/Exception;string access$000A(Lorg/jruby/rack/PoolingRackApplicationFactory;)Ljava/util/Queue;x0 access$100N(Lorg/jruby/rack/PoolingRackApplicationFactory;)Ljavax/servlet/ServletContext; SourceFile"PoolingRackApplicationFactory.java _` cd njava/util/LinkedList jk ab vwjruby.runtime.timeout.sec java/lang/StringBuilder$Info: using runtime pool timeout of      seconds     gh ih java/util/concurrent/Semaphore n lm |{  java/lang/InterruptedException*org/jruby/rack/RackInitializationExceptiontimeout: all listeners busy n  org/jruby/rack/RackApplication   ! " { #$% & ' ( )* !jruby.runtime.initializer.threads +,java/lang/Thread.org/jruby/rack/PoolingRackApplicationFactory$1 InnerClasses n-JRuby-Rack-App-Init-  . n/ 0 z{javax/servlet/ServletException,Error: unable to create application for pool 1minminIdle max maxActivejruby. .runtimes jruby.pool. Warning: no  runtimes specified.Info: received  runtimes =  2 34 56java/lang/Integer n7java/lang/Exception,org/jruby/rack/PoolingRackApplicationFactoryjava/lang/Object%org/jruby/rack/RackApplicationFactory longValue()Jappend-(Ljava/lang/String;)Ljava/lang/StringBuilder;(J)Ljava/lang/StringBuilder;toString()Ljava/lang/String;javax/servlet/ServletContextlog(Ljava/lang/String;)VintValue()I(IZ)Vjava/util/concurrent/TimeUnitSECONDSLjava/util/concurrent/TimeUnit; tryAcquire#(JLjava/util/concurrent/TimeUnit;)Z*(Ljava/lang/String;Ljava/lang/Throwable;)Vjava/util/QueueisEmpty()Zremove()Ljava/lang/Object;sizeadd(Ljava/lang/Object;)Zreleaseiterator()Ljava/util/Iterator;java/util/IteratorhasNextnextjava/util/CollectionsunmodifiableCollection.(Ljava/util/Collection;)Ljava/util/Collection;valueOf(I)Ljava/lang/Integer;B(Lorg/jruby/rack/PoolingRackApplicationFactory;Ljava/util/Queue;)V(I)Ljava/lang/StringBuilder;)(Ljava/lang/Runnable;Ljava/lang/String;)Vstartwait-(Ljava/lang/Object;)Ljava/lang/StringBuilder;getInitParameter&(Ljava/lang/String;)Ljava/lang/String;parseInt(Ljava/lang/String;)I(I)V!XYZ[\]^_`abcdefghihjklmnop`**Y**+ q/*,01rstubvwp*+* + * M, *, +Y******6*** ***Y***q>45789";C=K>S?Z@rAzCEFHr st_`xhyBz{p/*qKr sty#|{p[*!** !WL#Y$+%*YL*&*'(+ð+çM+,* )",FLGILLOLq* OQTRS%V,W8XGZQ\r }~[sty#pH*YM****,ñ*++W* *,,çN,-#B$?BBEBq"`a!b$d/e6f=hGirHstH{p4 * -qlr  stp:*YL*.M,/,0(N-1+ç :+/2262qpq$r-t9ur $:stp2*2qyr step/*3L*+4*YM*& *57,çN,-&)),)q $.r/st*d *fyBpG*8 M,9M>,/:Y;Y*+<Y=>?@ϱq @Fr*4\GstGd@h Gfep<YL=*(+* A+WNBYC-D+%(#q"%()4:r*) } 0\<st4d 4fyBep *YN*E-ç :-N"qr }~ st jkp3 *FGHqr  stp3 *IJHqr  stp*YK+L N-*YM, N-'*YN+O(*YP+Q-R-q!9=ar*stkhp!*+ST= UYVMWqr* \!st!p/*q%r tp/*q%r t ;PKd9 SSje$org/jruby/rack/RackApplication.classe1init()V Exceptionsdestroycall=(Ljavax/servlet/ServletRequest;)Lorg/jruby/rack/RackResponse; getRuntime()Lorg/jruby/Ruby; SourceFileRackApplication.javaorg/jruby/rack/RackApplicationjava/lang/Object*org/jruby/rack/RackInitializationException    PKd9"+org/jruby/rack/RackApplicationFactory.class1init!(Ljavax/servlet/ServletContext;)V ExceptionsnewApplication"()Lorg/jruby/rack/RackApplication;getApplicationfinishedWithApplication#(Lorg/jruby/rack/RackApplication;)VgetErrorApplicationdestroy()V SourceFileRackApplicationFactory.java%org/jruby/rack/RackApplicationFactoryjava/lang/Objectjavax/servlet/ServletException*org/jruby/rack/RackInitializationException     PKd9V^#org/jruby/rack/RackDispatcher.class-1 EXCEPTIONLjava/lang/String; ConstantValueDYNAMIC_REQS_ONLYprocessR(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V Exceptions SourceFileRackDispatcher.javaorg/jruby/rack/RackDispatcherjava/lang/Objectrack.exceptionrack.dynamic.requests.onlyjavax/servlet/ServletExceptionjava/io/IOException   PKd9uGr!org/jruby/rack/RackFilter$1.class 11  ! " # $% &'(this$0Lorg/jruby/rack/RackFilter;E(Lorg/jruby/rack/RackFilter;Ljavax/servlet/http/HttpServletRequest;)VCodeLineNumberTableLocalVariableTablethis InnerClassesLorg/jruby/rack/RackFilter$1;x0'Ljavax/servlet/http/HttpServletRequest; getPathInfo()Ljava/lang/String; SourceFileRackFilter.javaEnclosingMethod) *+ ,java/lang/StringBuilder -  ./.html 0org/jruby/rack/RackFilter$1,javax/servlet/http/HttpServletRequestWrapperorg/jruby/rack/RackFiltermaybeAppendHtmlToPathG(Ljavax/servlet/ServletRequest;)Ljavax/servlet/http/HttpServletRequest;*(Ljavax/servlet/http/HttpServletRequest;)V()Vappend-(Ljava/lang/String;)Ljava/lang/StringBuilder;toString   ? *+*,t  AY*u   PKd9̏!org/jruby/rack/RackFilter$2.class11  ! " # $% &'(this$0Lorg/jruby/rack/RackFilter;E(Lorg/jruby/rack/RackFilter;Ljavax/servlet/http/HttpServletRequest;)VCodeLineNumberTableLocalVariableTablethis InnerClassesLorg/jruby/rack/RackFilter$2;x0'Ljavax/servlet/http/HttpServletRequest;getServletPath()Ljava/lang/String; SourceFileRackFilter.javaEnclosingMethod) *+ ,java/lang/StringBuilder -  ./.html 0org/jruby/rack/RackFilter$2,javax/servlet/http/HttpServletRequestWrapperorg/jruby/rack/RackFiltermaybeAppendHtmlToPathG(Ljavax/servlet/ServletRequest;)Ljavax/servlet/http/HttpServletRequest;*(Ljavax/servlet/http/HttpServletRequest;)V()Vappend-(Ljava/lang/String;)Ljava/lang/StringBuilder;toString   ? *+*,{  AY*|   PKd9R`_Z5org/jruby/rack/RackFilter$ResponseStatusCapture.classZ17 + , - . / 0 134statusI+(Ljavax/servlet/http/HttpServletResponse;)VCodeLineNumberTableLocalVariableTablethisResponseStatusCapture InnerClasses1Lorg/jruby/rack/RackFilter$ResponseStatusCapture;response(Ljavax/servlet/http/HttpServletResponse; sendError(ILjava/lang/String;)VmessageLjava/lang/String; Exceptions5(I)V sendRedirect(Ljava/lang/String;)Vpath setStatus flushBuffer()VisError()Z access$0004(Lorg/jruby/rack/RackFilter$ResponseStatusCapture;)Zx0 SourceFileRackFilter.java $%  ! ! "#6/org/jruby/rack/RackFilter$ResponseStatusCapture-javax/servlet/http/HttpServletResponseWrapperjava/io/IOExceptionorg/jruby/rack/RackFilter    I *+*ȵ>; ?  H* BC  >* FG I *.*+JK L  !R***OP QS !]** *,VW XZ  "#> **]^ `  $%:*c &'/*: ()* 2 PKd9@l org/jruby/rack/RackFilter.class 71 K LM NO P QRS T UV W XY Z[ \]^ _` a bc K d e fgh jk jlmnResponseStatusCapture InnerClasses dispatcherLorg/jruby/rack/RackDispatcher;()VCodeLineNumberTableLocalVariableTablethisLorg/jruby/rack/RackFilter;"(Lorg/jruby/rack/RackDispatcher;)Vdispinit(Ljavax/servlet/FilterConfig;)VconfigLjavax/servlet/FilterConfig; ExceptionsodoFilter[(Ljavax/servlet/ServletRequest;Ljavax/servlet/ServletResponse;Ljavax/servlet/FilterChain;)VrequestLjavax/servlet/ServletRequest;responseLjavax/servlet/ServletResponse;chainLjavax/servlet/FilterChain; httpRequest'Ljavax/servlet/http/HttpServletRequest; httpResponse(Ljavax/servlet/http/HttpServletResponse;capture1Lorg/jruby/rack/RackFilter$ResponseStatusCapture;pdestroymaybeAppendHtmlToPathG(Ljavax/servlet/ServletRequest;)Ljavax/servlet/http/HttpServletRequest; servletPathLjava/lang/String;pathInfouri SourceFileRackFilter.java $% "#$org/jruby/rack/DefaultRackDispatcherq rs $t CD&javax/servlet/http/HttpServletResponse/org/jruby/rack/RackFilter$ResponseStatusCapture $uv 3w xy z%rack.dynamic.requests.only{ |}~ %javax/servlet/http/HttpServletRequest java/lang/StringBuilder  org/jruby/rack/RackFilter$1 $org/jruby/rack/RackFilter$2org/jruby/rack/RackFilterjava/lang/Objectjavax/servlet/Filterjavax/servlet/ServletExceptionjava/io/IOExceptionjavax/servlet/FilterConfiggetServletContext ()Ljavax/servlet/ServletContext;!(Ljavax/servlet/ServletContext;)V+(Ljavax/servlet/http/HttpServletResponse;)Vjavax/servlet/FilterChain@(Ljavax/servlet/ServletRequest;Ljavax/servlet/ServletResponse;)V access$0004(Lorg/jruby/rack/RackFilter$ResponseStatusCapture;)Zresetjava/lang/BooleanTRUELjava/lang/Boolean;javax/servlet/ServletRequest setAttribute'(Ljava/lang/String;Ljava/lang/Object;)Vorg/jruby/rack/RackDispatcherprocessR(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)VgetServletPath()Ljava/lang/String; getPathInfoappend-(Ljava/lang/String;)Ljava/lang/StringBuilder;toStringjava/lang/String lastIndexOf(I)IE(Lorg/jruby/rack/RackFilter;Ljavax/servlet/http/HttpServletRequest;)V!"#$%&3*' ( )*$+&F **+'!" #( )* ,#-.&J*Y+' '(()*/01234&L*+:,:Y :-  $ + *+'& ,- ./"0*112<3K5(HL)*L56L78L9:E;< ?=>4?@1A2B%&+'8( )*CD&a+M,N,:-:Y:./Y*,M Y*,M,'. hi jkmn2pCqHrUy_(>a)*a56\;< UEFMGFJHFIJ! PKd9~E0org/jruby/rack/RackInitializationException.classx1D ( )* + ,- ./ 012 +3 4 .5 / /67((Lorg/jruby/exceptions/RaiseException;)VCodeLineNumberTableLocalVariableTablethis,Lorg/jruby/rack/RackInitializationException;re%Lorg/jruby/exceptions/RaiseException;exceptionMessage9(Lorg/jruby/exceptions/RaiseException;)Ljava/lang/String;stLjava/lang/StringBuilder;bLjava/io/ByteArrayOutputStream;*(Ljava/lang/String;Ljava/lang/Throwable;)VmsgLjava/lang/String;exLjava/lang/Throwable; SourceFile RackInitializationException.java  !java/lang/StringBuilder 89 :;< => ?@ java/io/ByteArrayOutputStreamjava/io/PrintStream A BC*org/jruby/rack/RackInitializationExceptionjava/lang/Exception()V#org/jruby/exceptions/RaiseException getException()Lorg/jruby/RubyException;org/jruby/RubyExceptiontoString()Ljava/lang/String;append-(Ljava/lang/String;)Ljava/lang/StringBuilder;(Ljava/io/OutputStream;)VprintBacktrace(Ljava/io/PrintStream;)V!B *++     D*AYL+*W Y M* Y, +,W+" %4=B  6% D!I*+,  ! "#$%&'PKd9u9w)$!org/jruby/rack/RackResponse.class$1  getStatus()I getHeaders()Ljava/util/Map;getBody()Ljava/lang/String;respond+(Ljavax/servlet/http/HttpServletResponse;)V SourceFileRackResponse.javaorg/jruby/rack/RackResponsejava/lang/Object   PKd919 org/jruby/rack/RackServlet.classn19 $ %& '( )*+ ,-./ dispatcherLorg/jruby/rack/RackDispatcher;()VCodeLineNumberTableLocalVariableTablethisLorg/jruby/rack/RackServlet;"(Lorg/jruby/rack/RackDispatcher;)Vinit (Ljavax/servlet/ServletConfig;)VconfigLjavax/servlet/ServletConfig;service@(Ljavax/servlet/ServletRequest;Ljavax/servlet/ServletResponse;)VrequestLjavax/servlet/ServletRequest;responseLjavax/servlet/ServletResponse; Exceptions01 SourceFileRackServlet.java  $org/jruby/rack/DefaultRackDispatcher2 34 5%javax/servlet/http/HttpServletRequest&javax/servlet/http/HttpServletResponse6 78org/jruby/rack/RackServletjavax/servlet/http/HttpServletjavax/servlet/ServletExceptionjava/io/IOExceptionjavax/servlet/ServletConfiggetServletContext ()Ljavax/servlet/ServletContext;!(Ljavax/servlet/ServletContext;)Vorg/jruby/rack/RackDispatcherprocessR(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V!   3*   F **+   J*Y+ $%T*+, *+  !"#PKd91+uID/org/jruby/rack/RackServletContextListener.classD1X 3 4 56 78 9: ;<= 9> 9?@ A 9BCD 3 EFGH FACTORY_KEYLjava/lang/String; ConstantValuefactory'Lorg/jruby/rack/RackApplicationFactory;()VCodeLineNumberTableLocalVariableTablethis+Lorg/jruby/rack/RackServletContextListener;*(Lorg/jruby/rack/RackApplicationFactory;)VfactoryForTestcontextInitialized&(Ljavax/servlet/ServletContextEvent;)VexLjava/lang/Exception;ctxEvent#Ljavax/servlet/ServletContextEvent;ctxLjavax/servlet/ServletContext;faccontextDestroyednewApplicationFactoryG(Ljavax/servlet/ServletContext;)Lorg/jruby/rack/RackApplicationFactory;context SourceFileRackServletContextListener.java  I JK ./ rack.factoryL MN OPjava/lang/Exception(Error: application initialization failed QR ST%org/jruby/rack/RackApplicationFactory U VW+org/jruby/rack/SharedRackApplicationFactory,org/jruby/rack/DefaultRackApplicationFactory ")org/jruby/rack/RackServletContextListenerjava/lang/Object$javax/servlet/ServletContextListener!javax/servlet/ServletContextEventgetServletContext ()Ljavax/servlet/ServletContext;javax/servlet/ServletContext setAttribute'(Ljava/lang/String;Ljava/lang/Object;)Vinit!(Ljavax/servlet/ServletContext;)Vlog*(Ljava/lang/String;Ljava/lang/Throwable;)V getAttribute&(Ljava/lang/String;)Ljava/lang/Object;destroyremoveAttribute(Ljava/lang/String;)V!< **   !"F **+  ! #$%++M*,N,--,:,  ""# $&)' (**4 &'+ !+()&*+ ,-%$+M,  N-- ,-.012#4*$ !$()*+,./W**YY78 ; !0+12PKd9M4/org/jruby/rack/RackTag$1.class/1= & '() * $+ ,- $. /01this$0Lorg/jruby/rack/RackTag;B(Lorg/jruby/rack/RackTag;Ljavax/servlet/http/HttpServletRequest;)VCodeLineNumberTableLocalVariableTablethis InnerClassesLorg/jruby/rack/RackTag$1;x0'Ljavax/servlet/http/HttpServletRequest; getMethod()Ljava/lang/String; getRequestURI getPathInfogetQueryStringgetServletPath SourceFile RackTag.javaEnclosingMethod2 34  5GETjava/lang/StringBuilder 6 78 9:? ;8 <org/jruby/rack/RackTag$1,javax/servlet/http/HttpServletRequestWrapperorg/jruby/rack/RackTagdoEndTag()I*(Ljavax/servlet/http/HttpServletRequest;)V()V access$000,(Lorg/jruby/rack/RackTag;)Ljava/lang/String;append-(Ljava/lang/String;)Ljava/lang/StringBuilder; access$100toString ? *+*,!  - N$Y**   $2* 2*    - ! !"#$%  PKd9ձ|c ^ org/jruby/rack/RackTag.class^ 1p 8 9 : ; <=> ?@A BC <FG H IJ <K LM NO PQR STUpathLjava/lang/String;params()VCodeLineNumberTableLocalVariableTablethisLorg/jruby/rack/RackTag;setPath(Ljava/lang/String;)V setParamsdoEndTag()Irequest'Ljavax/servlet/http/HttpServletRequest;resultLorg/jruby/rack/RackResponse;factory'Lorg/jruby/rack/RackApplicationFactory;app Lorg/jruby/rack/RackApplication;eLjava/lang/Exception; Exceptions access$000,(Lorg/jruby/rack/RackTag;)Ljava/lang/String;x0 access$100 SourceFile RackTag.java    VWX YZ rack.factory[ \]%org/jruby/rack/RackApplicationFactory ^_org/jruby/rack/RackTag$1 InnerClasses `a%javax/servlet/http/HttpServletRequest bc de fgh ijk l# mnjava/lang/Exceptionjavax/servlet/jsp/JspException oorg/jruby/rack/RackTag#javax/servlet/jsp/tagext/TagSupport pageContextLjavax/servlet/jsp/PageContext;javax/servlet/jsp/PageContextgetServletContext ()Ljavax/servlet/ServletContext;javax/servlet/ServletContext getAttribute&(Ljava/lang/String;)Ljava/lang/Object;getApplication"()Lorg/jruby/rack/RackApplication; getRequest ()Ljavax/servlet/ServletRequest;B(Lorg/jruby/rack/RackTag;Ljavax/servlet/http/HttpServletRequest;)Vorg/jruby/rack/RackApplicationcall=(Ljavax/servlet/ServletRequest;)Lorg/jruby/rack/RackResponse;getOut()Ljavax/servlet/jsp/JspWriter;org/jruby/rack/RackResponsegetBody()Ljava/lang/String;javax/servlet/jsp/JspWriterwritefinishedWithApplication#(Lorg/jruby/rack/RackApplication;)V(Ljava/lang/Throwable;)V!/*  !"#>*+   !$#>*+  !%& l*L+ M Y** N,-:*+,:+, LY+FPPRP\_2 ,#5$F&M'P&\*_(`)i+>,'(5)*J+,C-.` /0l !123/* 4!53/* 4!67E  PKd9org/jruby/rack/rails/PKd9<1org/jruby/rack/SharedRackApplicationFactory.class1E / 0 1 2 345 678 9 2 : ;<=>? realFactory'Lorg/jruby/rack/RackApplicationFactory; application Lorg/jruby/rack/RackApplication;*(Lorg/jruby/rack/RackApplicationFactory;)VCodeLineNumberTableLocalVariableTablethis-Lorg/jruby/rack/SharedRackApplicationFactory;factoryinit!(Ljavax/servlet/ServletContext;)Vex,Lorg/jruby/rack/RackInitializationException;servletContextLjavax/servlet/ServletContext; ExceptionsnewApplication"()Lorg/jruby/rack/RackApplication;getApplicationfinishedWithApplication#(Lorg/jruby/rack/RackApplication;)VappgetErrorApplicationdestroy()V SourceFile!SharedRackApplicationFactory.java ,   &% *org/jruby/rack/RackInitializationException,unable to create shared application instance@ ABjavax/servlet/ServletException C *%D +,+org/jruby/rack/SharedRackApplicationFactoryjava/lang/Object%org/jruby/rack/RackApplicationFactoryjavax/servlet/ServletContextlog*(Ljava/lang/String;Ljava/lang/Throwable;)V(Ljava/lang/Throwable;)Vorg/jruby/rack/RackApplication!F **+   .*+**M+, Y,  $-   ..!"# $%/* # #&%/*' #'(5+)*%4 * .  +,8 *  2 3  -.PKd9S4id4org/jruby/rack/merb/MerbRackApplicationFactory.classd1"   ()VCodeLineNumberTableLocalVariableTablethis0Lorg/jruby/rack/merb/MerbRackApplicationFactory;createApplicationObject9(Lorg/jruby/Ruby;)Lorg/jruby/runtime/builtin/IRubyObject;runtimeLorg/jruby/Ruby; SourceFileMerbRackApplicationFactory.java  load 'jruby/rack/boot/merb.rb'  run JRuby::Rack::MerbFactory.new !.org/jruby/rack/merb/MerbRackApplicationFactory,org/jruby/rack/DefaultRackApplicationFactoryorg/jruby/Ruby evalScriptlet;(Ljava/lang/String;)Lorg/jruby/runtime/builtin/IRubyObject;createRackServletWrapperK(Lorg/jruby/Ruby;Ljava/lang/String;)Lorg/jruby/runtime/builtin/IRubyObject;!  /*    G+W*+   PKd9O4org/jruby/rack/merb/MerbServletContextListener.class1   ()VCodeLineNumberTableLocalVariableTablethis0Lorg/jruby/rack/merb/MerbServletContextListener;newApplicationFactoryG(Ljavax/servlet/ServletContext;)Lorg/jruby/rack/RackApplicationFactory;contextLjavax/servlet/ServletContext; SourceFileMerbServletContextListener.java  +org/jruby/rack/SharedRackApplicationFactory.org/jruby/rack/merb/MerbRackApplicationFactory .org/jruby/rack/merb/MerbServletContextListener)org/jruby/rack/RackServletContextListener*(Lorg/jruby/rack/RackApplicationFactory;)V!  /*    CYY   PKd9¼Dpk6org/jruby/rack/rails/RailsRackApplicationFactory.classk1"   ()VCodeLineNumberTableLocalVariableTablethis2Lorg/jruby/rack/rails/RailsRackApplicationFactory;createApplicationObject9(Lorg/jruby/Ruby;)Lorg/jruby/runtime/builtin/IRubyObject;runtimeLorg/jruby/Ruby; SourceFile RailsRackApplicationFactory.java  load 'jruby/rack/boot/rails.rb' !run JRuby::Rack::RailsFactory.new !0org/jruby/rack/rails/RailsRackApplicationFactory,org/jruby/rack/DefaultRackApplicationFactoryorg/jruby/Ruby evalScriptlet;(Ljava/lang/String;)Lorg/jruby/runtime/builtin/IRubyObject;createRackServletWrapperK(Lorg/jruby/Ruby;Ljava/lang/String;)Lorg/jruby/runtime/builtin/IRubyObject;!  /*    G+W*+   PKd9gJ@;6org/jruby/rack/rails/RailsServletContextListener.class;1A "# $% &' () (*+ (,-. " /0 /12()VCodeLineNumberTableLocalVariableTablethis2Lorg/jruby/rack/rails/RailsServletContextListener;newApplicationFactoryG(Ljavax/servlet/ServletContext;)Lorg/jruby/rack/RackApplicationFactory;eLjava/lang/Exception;contextLjavax/servlet/ServletContext; maxRuntimesLjava/lang/Integer; SourceFile RailsServletContextListener.java jruby.max.runtimes3 456 789 :; <=java/lang/Exception >?+org/jruby/rack/SharedRackApplicationFactory0org/jruby/rack/rails/RailsRackApplicationFactory @,org/jruby/rack/PoolingRackApplicationFactory0org/jruby/rack/rails/RailsServletContextListener)org/jruby/rack/RackServletContextListenerjavax/servlet/ServletContextgetInitParameter&(Ljava/lang/String;)Ljava/lang/String;java/lang/StringtoString()Ljava/lang/String;java/lang/IntegerparseInt(Ljava/lang/String;)IvalueOf(I)Ljava/lang/Integer;intValue()I*(Lorg/jruby/rack/RackApplicationFactory;)V!/* BM+MN,, Y Y Y Y $3*BB@ !PKd9_3."org/jruby/webapp/FileServlet.class.1  ()VCodeLineNumberTableLocalVariableTablethisLorg/jruby/webapp/FileServlet; SourceFileFileServlet.java org/jruby/webapp/FileServletorg/jruby/rack/RackServlet!/*     PKd9d_+org/jruby/webapp/RailsContextListener.class_1  ()VCodeLineNumberTableLocalVariableTablethis'Lorg/jruby/webapp/RailsContextListener; SourceFileRailsContextListener.java %org/jruby/webapp/RailsContextListener0org/jruby/rack/rails/RailsServletContextListener!/*     PKd961#org/jruby/webapp/RailsServlet.class11  ()VCodeLineNumberTableLocalVariableTablethisLorg/jruby/webapp/RailsServlet; SourceFileRailsServlet.java org/jruby/webapp/RailsServletorg/jruby/rack/RackServlet!/*     PKd9cgi/PKd9jruby/PKd9rack/PKd9 rack.rb a# Copyright (C) 2007, 2008 Christian Neukirchen # # Rack is freely distributable under the terms of an MIT-style license. # See COPYING or http://www.opensource.org/licenses/mit-license.php. $: << File.expand_path(File.dirname(__FILE__)) # The Rack main module, serving as a namespace for all core Rack # modules and classes. # # All modules meant for use in your application are autoloaded here, # so it should be enough just to require rack.rb in your code. module Rack # The Rack protocol version number implemented. VERSION = [0,1] # Return the Rack protocol version as a dotted string. def self.version VERSION.join(".") end # Return the Rack release as a dotted string. def self.release "0.4" end autoload :Builder, "rack/builder" autoload :Cascade, "rack/cascade" autoload :CommonLogger, "rack/commonlogger" autoload :File, "rack/file" autoload :Deflater, "rack/deflater" autoload :Directory, "rack/directory" autoload :ForwardRequest, "rack/recursive" autoload :Handler, "rack/handler" autoload :Lint, "rack/lint" autoload :Recursive, "rack/recursive" autoload :Reloader, "rack/reloader" autoload :ShowExceptions, "rack/showexceptions" autoload :ShowStatus, "rack/showstatus" autoload :Static, "rack/static" autoload :URLMap, "rack/urlmap" autoload :Utils, "rack/utils" autoload :MockRequest, "rack/mock" autoload :MockResponse, "rack/mock" autoload :Request, "rack/request" autoload :Response, "rack/response" module Auth autoload :Basic, "rack/auth/basic" autoload :AbstractRequest, "rack/auth/abstract/request" autoload :AbstractHandler, "rack/auth/abstract/handler" autoload :OpenID, "rack/auth/openid" module Digest autoload :MD5, "rack/auth/digest/md5" autoload :Nonce, "rack/auth/digest/nonce" autoload :Params, "rack/auth/digest/params" autoload :Request, "rack/auth/digest/request" end end module Session autoload :Cookie, "rack/session/cookie" autoload :Pool, "rack/session/pool" autoload :Memcache, "rack/session/memcache" end # *Adapters* connect Rack with third party web frameworks. # # Rack includes an adapter for Camping, see README for other # frameworks supporting Rack in their code bases. # # Refer to the submodules for framework-specific calling details. module Adapter autoload :Camping, "rack/adapter/camping" end end PKd9 cgi/session/PKd95n !cgi/session/java_servlet_store.rb class CGI #:nodoc:all class Session class JavaServletStore RAILS_SESSION_KEY = "__current_rails_session" def initialize(session, option=nil) @java_request = option["java_servlet_request"] if option unless @java_request raise 'JavaServletStore requires that HttpServletRequest is made available to the session' end @digest = option['digest'] || 'SHA1' @session_data = {} end # Restore session state from the Java session def restore @session_data = {} java_session = @java_request.getSession(false) if java_session java_session.getAttributeNames.each do |k| if k == RAILS_SESSION_KEY marshalled_bytes = java_session.getAttribute(RAILS_SESSION_KEY) if marshalled_bytes data = Marshal.load(String.from_java_bytes(marshalled_bytes)) @session_data.update data if Hash === data end else @session_data[k] = java_session.getAttribute(k) end end end @session_data end # Save session state to the Java session def update java_session = @java_request.getSession(true) hash = @session_data.dup hash.delete_if do |k,v| if String === k case v when String, Numeric, true, false, nil java_session.setAttribute k, v true else if v.respond_to?(:java_object) java_session.setAttribute k, v true else false end end end end unless hash.empty? marshalled_string = Marshal.dump(hash) marshalled_bytes = marshalled_string.to_java_bytes java_session.setAttribute(RAILS_SESSION_KEY, marshalled_bytes) end end # Update and close the Java session entry def close update end # Delete the Java session entry def delete java_session = @java_request.getSession(false) java_session.invalidate if java_session end def generate_digest(data) java_session = @java_request.getSession(true) @secret ||= java_session.getAttribute("__rails_secret") unless @secret @secret = java_session.getId + java_session.getLastAccessedTime.to_s java_session.setAttribute("__rails_secret", @secret) end OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new(@digest), @secret, data) end # The session state def data @session_data end def []=(k, v) @session_data[k] = v end def [](k) @session_data[k] end def each(&b) @session_data.each(&b) end private # Attempts to redirect any messages to the data object. def method_missing(name, *args, &block) @session_data.send(name, *args, &block) end end end end PKd9 jruby/rack/PKd9B750 jruby/rack.rb0#-- # Copyright 2007-2008 Sun Microsystems, Inc. # This source code is available under the MIT license. # See the file LICENSE.txt for details. #++ require 'rack' require 'time' # some of rack uses Time#rfc822 but doesn't pull this in require 'jruby/rack/servlet_helper' require 'jruby/rack/servlet_ext'PKd9jruby/rack/boot/PKd9 3 jruby/rack/merb.rb [require 'jruby/rack' require 'cgi/session/java_servlet_store' module JRuby module Rack class MerbServletHelper < ::JRuby::Rack::ServletHelper attr_reader :merb_environment, :merb_root def initialize(servlet_context = nil) super @merb_root = @servlet_context.getInitParameter('merb.root') @merb_root ||= '/WEB-INF' @merb_root = expand_root_path @merb_root @merb_environment = @servlet_context.getInitParameter('merb.environment') @merb_environment ||= 'production' end def load_environment load_merb setup_adapter setup_sessions start_merb end def load_merb framework = File.expand_path(File.join(@merb_root, 'framework')) if File.directory?(framework) logger.debug("Trying to load Merb from #{framework}") core = File.join(framework, 'merb-core') if File.directory?(core) $LOAD_PATH.push File.join(core, 'lib') end more = File.join(framework, 'merb-more') if File.directory?(more) Dir.new(more).select {|d| d =~ /merb-/}.each do |d| $LOAD_PATH.push File.join(more, d, 'lib') end end plugins = File.join(framework, 'merb-plugins') if File.directory?(plugins) Dir.new(plugins).select {|d| d =~ /merb_/}.each do |d| $LOAD_PATH.push File.join(plugins, d, 'lib') end end else logger.debug("Didn't find a framework/ directory, falling back to Rubygems") require 'rubygems' end require 'merb-core' require 'merb-core/rack' Merb.frozen! end def setup_adapter logger.debug('Registering Merb servlet adapter') Merb::Rack::Adapter.register %w{servlet}, :Servlet end def setup_sessions logger.debug('Registering Merb servlet sessions') Merb.register_session_type 'servlet', 'jruby/rack/merb', 'Using Java servlet sessions' end def start_merb logger.debug('Starting Merb') Merb.start :merb_root => merb_root, :environment => merb_environment, :adapter => 'servlet' end end class MerbFactory def self.new MerbServletHelper.instance.load_environment ::Rack::Builder.new { run ::Merb::Config[:app] }.to_app end end end end # Merb likes to hardcode things into the Merb:: namespace. module Merb module Rack class Servlet def self.start(opts={}) Merb.logger.info("Using Java servlet adapter") if self == Merb::Rack::Servlet Merb.logger.flush end end end module SessionMixin def setup_session Merb.logger.info("Setting Up Java servlet session") opts = {'java_servlet_request' => request.env['java.servlet_request']} request.session = CGI::Session::JavaServletStore.new(nil, opts) request.session.restore end def finalize_session Merb.logger.info("Finalizing Java servlet session") request.session.update end def session_store_type "servlet" end end end PKd9,'lgjruby/rack/rails.rbg#-- # Copyright 2007-2008 Sun Microsystems, Inc. # This source code is available under the MIT license. # See the file LICENSE.txt for details. #++ require 'jruby/rack' module JRuby module Rack class RailsServletHelper < ServletHelper attr_accessor :rails_env, :rails_root def initialize(servlet_context = nil) super @rails_root = @servlet_context.getInitParameter 'rails.root' @rails_root ||= '/WEB-INF' @rails_root = expand_root_path @rails_root @rails_env = @servlet_context.getInitParameter 'rails.env' @rails_env ||= 'production' ENV['RAILS_ROOT'] = @rails_root ENV['RAILS_ENV'] = @rails_env silence_warnings { Object.const_set("PUBLIC_ROOT", public_root) } end def load_environment require 'cgi/session/java_servlet_store' require 'jruby/rack/rails_boot' load File.join(rails_root, 'config', 'environment.rb') require 'dispatcher' require 'jruby/rack/rails_ext' setup_sessions setup_logger end # This hook method is called back from within the mechanism installed # by rails_boot above. We're setting appropriate defaults for the # servlet environment here that can still be overridden (if desired) in # the application's environment files. def boot_for_servlet_environment(initializer) initializer_class = initializer.class initializer_class.module_eval do alias_method :require_frameworks_without_servlet_env, :require_frameworks def require_frameworks_with_servlet_env JRuby::Rack::RailsServletHelper.instance.before_require_frameworks require_frameworks_without_servlet_env JRuby::Rack::RailsServletHelper.instance.setup_actionpack end alias_method :require_frameworks, :require_frameworks_with_servlet_env end end def before_require_frameworks Rails.public_path = PUBLIC_ROOT if defined?(Rails.public_path) end def setup_actionpack ActionController::Base.session_store = :java_servlet_store unless defined?(Rails.public_path) ActionController::Base.page_cache_directory = PUBLIC_ROOT silence_warnings do asset_tag_helper = ActionView::Helpers::AssetTagHelper asset_tag_helper.const_set("ASSETS_DIR", PUBLIC_ROOT) asset_tag_helper.const_set("JAVASCRIPTS_DIR", "#{PUBLIC_ROOT}/javascripts") asset_tag_helper.const_set("STYLESHEETS_DIR", "#{PUBLIC_ROOT}/stylesheets") end end end def setup_sessions if default_sessions? session_options[:database_manager] = java_servlet_store end # Turn off default cookies when using Java sessions if java_sessions? session_options[:no_cookies] = true end end def setup_logger if defined?(::RAILS_DEFAULT_LOGGER) class << ::RAILS_DEFAULT_LOGGER # Make these accessible to wire in the log device public :instance_variable_get, :instance_variable_set end # use config.logger? if defined?(ActiveSupport::BufferedLogger) # Rails 2.x old_device = ::RAILS_DEFAULT_LOGGER.instance_variable_get "@log" old_device.close rescue nil ::RAILS_DEFAULT_LOGGER.instance_variable_set "@log", logdev else # Rails 1.x old_device = ::RAILS_DEFAULT_LOGGER.instance_variable_get "@logdev" old_device.close rescue nil ::RAILS_DEFAULT_LOGGER.instance_variable_set "@logdev", Logger::LogDevice.new(logdev) end end end def session_options @session_options ||= SESSION_OPTIONS end def session_options_for_request(env) options = session_options.dup options[:java_servlet_request] = env['java.servlet_request'] options end def java_sessions? session_options[:database_manager] == java_servlet_store end def default_sessions? session_options[:database_manager] == default_store end def default_store defined?(::CGI::Session::PStore) && CGI::Session::PStore end def java_servlet_store CGI::Session::JavaServletStore end def options {:public => public_root, :root => rails_root, :environment => rails_env} end end Bootstrap = RailsServletHelper class RailsSetup def initialize(app, servlet_helper) @app = app @servlet_helper = servlet_helper end def call(env) env['rails.session_options'] = @servlet_helper.session_options_for_request(env) env['HTTPS'] = 'on' if env['rack.url_scheme'] == 'https' relative_url_root = env['java.servlet_request'].getContextPath if relative_url_root && !relative_url_root.empty? env['RAILS_RELATIVE_URL_ROOT'] = relative_url_root ActionController::Base.relative_url_root = relative_url_root if ActionController::Base.respond_to?(:relative_url_root=) end @app.call(env) end end class RailsFactory def self.new helper = RailsServletHelper.instance helper.load_environment ::Rack::Builder.new { use RailsSetup, helper run ::Rack::Adapter::Rails.new(helper.options) }.to_app end end end endPKd9jruby/rack/rails_boot.rb#-- # Copyright 2007-2008 Sun Microsystems, Inc. # This source code is available under the MIT license. # See the file LICENSE.txt for details. #++ module Rails # This hook code exists to allow us to hook into the Rails boot sequence so # that we can set some additional defaults that are more friendly to the servlet # environment, but still can be overridden by the application in the Rails # initializer. # # Only for Rails 2.0, unfortunately. This code is mildly evil, but we're hoping # the Rails booter code won't change too much. class BootHook def initialize(real_boot) @real_boot = real_boot end def run result = @real_boot.run JRuby::Rack::RailsServletHelper.instance.boot_for_servlet_environment(result) result end def custom_boot end end class Boot # Hook into methods added for Rails::Boot, and redefine Rails.pick_boot. # Only needs to be done once, so remove the method_added hook when done. def self.method_added(meth) class << ::Rails alias_method :original_pick_boot, :pick_boot def pick_boot BootHook.new(original_pick_boot) end end class << self; remove_method :method_added; end end end endPKd96(#jruby/rack/rails_ext.rb##-- # Copyright 2007-2008 Sun Microsystems, Inc. # This source code is available under the MIT license. # See the file LICENSE.txt for details. #++ require 'action_controller' module ActionController class CgiRequest #:nodoc: # Replace session_options writer to merge session options # With ones passed into request (so we can preserve the # java servlet request) def session_options=(opts) if opts == false @session_options = false elsif @session_options @session_options.update(opts) else @session_options = opts end end end class Base def servlet_request request.env['java.servlet_request'] end def forward_to(url) @performed_render = true req = servlet_request response.headers['Forward'] = proc do |resp| req.getRequestDispatcher(url).forward(req, resp) end end end module Rescue # Rails 2.0 static rescue files def render_optional_error_file(status_code) #:nodoc: status = interpret_status(status_code) path = "#{PUBLIC_ROOT}/#{status[0,3]}.html" if File.exists?(path) render :file => path, :status => status else head status end end def rescue_action_in_public(exception) #:nodoc: if respond_to?(:render_optional_error_file) # Rails 2 render_optional_error_file response_code_for_rescue(exception) else # Rails 1 case exception when RoutingError, UnknownAction render_text(IO.read(File.join(PUBLIC_ROOT, '404.html')), "404 Not Found") else render_text(IO.read(File.join(PUBLIC_ROOT, '500.html')), "500 Internal Error") end end end end end module JRuby::Rack SESSION_OPTIONS = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS end PKd9~ŭjruby/rack/servlet_ext.rbz#-- # Copyright 2007-2008 Sun Microsystems, Inc. # This source code is available under the MIT license. # See the file LICENSE.txt for details. #++ # Ruby-friendly extensions to the servlet API. module Java::JavaxServletHttp::HttpServletRequest # Fetch an attribute from the servlet request. def [](key) getAttribute(key.to_s) end # Set an attribute in the servlet request. def []=(key, val) setAttribute(key.to_s, val) end # Retrieve all the attribute names (keys) from the servlet request. def keys getAttributeNames.to_a end end module Java::JavaxServletHttp::HttpSession # Fetch an attribute from the session. def [](key) getAttribute(key.to_s) end # Set an attribute in the session. def []=(key, val) setAttribute(key.to_s, val) end # Retrieve all the attribute names (keys) from the session. def keys getAttributeNames.to_a end end PKd9.jruby/rack/servlet_helper.rbb#-- # Copyright 2007-2008 Sun Microsystems, Inc. # This source code is available under the MIT license. # See the file LICENSE.txt for details. #++ module JRuby module Rack def self.silence_warnings oldv, $VERBOSE = $VERBOSE, nil begin yield ensure $VERBOSE = oldv end end class Response include Java::org.jruby.rack.RackResponse def initialize(arr) @status, @headers, @body = *arr end def getStatus @status end def getHeaders @headers end def getBody b = "" @body.each {|part| b << part } b end def respond(response) if fwd = @headers["Forward"] fwd.call(response) else write_status(response) write_headers(response) write_body(response) end end def write_status(response) response.setStatus(@status.to_i) end def write_headers(response) @headers.each do |k,v| case k when /^Content-Type$/i response.setContentType(v.to_s) when /^Content-Length$/i response.setContentLength(v.to_i) else if v.respond_to?(:each) v.each {|val| response.addHeader(k.to_s, val) } else case v when Numeric response.addIntHeader(k.to_s, v.to_i) when Time response.addDateHeader(k.to_s, v.to_i * 1000) else response.addHeader(k.to_s, v.to_s) end end end end end def write_body(response) stream = response.getOutputStream begin @body.each do |el| stream.write(el.to_java_bytes) end rescue LocalJumpError => e # HACK: deal with objects that don't comply with Rack specification @body = [@body.to_s] retry end end end class ServletLog def initialize(context = $servlet_context) @context = context end def puts(msg) write msg.to_s end def write(msg) @context.log(msg) end def flush; end def close; end end class ServletHelper attr_reader :public_root, :gem_path def initialize(servlet_context = nil) @servlet_context = servlet_context || $servlet_context @public_root = @servlet_context.getInitParameter 'public.root' @public_root ||= @servlet_context.getInitParameter 'files.prefix' # Goldspike @public_root ||= '/WEB-INF/public' @public_root = "/#{@public_root}" unless @public_root =~ %r{^/} @public_root = expand_root_path @public_root @public_root = @public_root.chomp("/") $0 = File.join(root_path, "web.xml") @gem_path = @servlet_context.getInitParameter 'gem.path' @gem_path ||= '/WEB-INF/gems' @gem_path = expand_root_path @gem_path setup_gems ServletHelper.instance = self end def root_path @root_path ||= real_path('/WEB-INF') end def real_path(path) @servlet_context.getRealPath(path) end def expand_root_path(path) if path =~ %r{^/WEB-INF} path.sub(%r{^/WEB-INF}, root_path) else real_path path end end def logdev @logdev ||= ServletLog.new @servlet_context end def logger @logger ||= begin; require 'logger'; Logger.new(logdev); end end def setup_gems $LOAD_PATH << 'META-INF/jruby.home/lib/ruby/site_ruby/1.8' ENV['GEM_PATH'] = @gem_path end def change_to_root_directory Dir.chdir(root_path) if File.directory?(root_path) end def silence_warnings(&block) JRuby::Rack.silence_warnings(&block) end def self.instance @instance ||= self.new end def self.instance=(inst) @instance = inst end end class Errors EXCEPTION = org.jruby.rack.RackDispatcher::EXCEPTION def initialize(file_server) @file_server = file_server end def call(env) [code = response_code(env), *response_content(env, code)] end def response_code(env) exc = env[EXCEPTION] if exc env['rack.showstatus.detail'] = exc.getMessage if exc.getCause.kind_of?(Java::JavaLang::InterruptedException) 503 else 500 end else 500 end end def response_content(env, code) @responses ||= Hash.new do |h,k| env["PATH_INFO"] = "/#{code}.html" response = @file_server.call(env) body = response[2] unless Array === body newbody = "" body.each do |chunk| newbody << chunk end response[2] = [newbody] end h[k] = response end response = @responses[code] if response[0] != 404 env["rack.showstatus.detail"] = nil response[1..2] else [{}, []] end end end class ErrorsApp def self.new ::Rack::Builder.new { use ::Rack::ShowStatus run Errors.new(::Rack::File.new(ServletHelper.instance.public_root)) }.to_app end end end endPKd9˟ojruby/rack/boot/merb.rb#-- # Copyright 2007-2008 Sun Microsystems, Inc. # This source code is available under the MIT license. # See the file LICENSE.txt for details. #++ require 'jruby/rack/merb' module JRuby::Rack silence_warnings do const_set('Bootstrap', MerbServletHelper) end end PKd9/Sjruby/rack/boot/rack.rb#-- # Copyright 2007-2008 Sun Microsystems, Inc. # This source code is available under the MIT license. # See the file LICENSE.txt for details. #++ module JRuby::Rack Bootstrap = ServletHelper unless defined?(Bootstrap) endPKd9pjruby/rack/boot/rails.rb#-- # Copyright 2007-2008 Sun Microsystems, Inc. # This source code is available under the MIT license. # See the file LICENSE.txt for details. #++ require 'rack/adapter/rails' module JRuby::Rack silence_warnings do const_set('Bootstrap', RailsServletHelper) end end PKd9 rack/adapter/PKd9 rack/auth/PKd9rack/builder.rbmodule Rack # Rack::Builder implements a small DSL to iteratively construct Rack # applications. # # Example: # # app = Rack::Builder.new { # use Rack::CommonLogger # use Rack::ShowExceptions # map "/lobster" do # use Rack::Lint # run Rack::Lobster.new # end # } # # +use+ adds a middleware to the stack, +run+ dispatches to an application. # You can use +map+ to construct a Rack::URLMap in a convenient way. class Builder def initialize(&block) @ins = [] instance_eval(&block) if block_given? end def use(middleware, *args, &block) @ins << if block_given? lambda { |app| middleware.new(app, *args, &block) } else lambda { |app| middleware.new(app, *args) } end end def run(app) @ins << app #lambda { |nothing| app } end def map(path, &block) if @ins.last.kind_of? Hash @ins.last[path] = Rack::Builder.new(&block).to_app else @ins << {} map(path, &block) end end def to_app @ins[-1] = Rack::URLMap.new(@ins.last) if Hash === @ins.last inner_app = @ins.last @ins[0...-1].reverse.inject(inner_app) { |a, e| e.call(a) } end def call(env) to_app.call(env) end end end PKd9rack/cascade.rbmodule Rack # Rack::Cascade tries an request on several apps, and returns the # first response that is not 404 (or in a list of configurable # status codes). class Cascade attr_reader :apps def initialize(apps, catch=404) @apps = apps @catch = [*catch] end def call(env) status = headers = body = nil raise ArgumentError, "empty cascade" if @apps.empty? @apps.each { |app| begin status, headers, body = app.call(env) break unless @catch.include?(status.to_i) end } [status, headers, body] end def add app @apps << app end def include? app @apps.include? app end alias_method :<<, :add end end PKd9wrack/commonlogger.rbmodule Rack # Rack::CommonLogger forwards every request to an +app+ given, and # logs a line in the Apache common log format to the +logger+, or # rack.errors by default. class CommonLogger def initialize(app, logger=nil) @app = app @logger = logger end def call(env) dup._call(env) end def _call(env) @env = env @logger ||= self @time = Time.now @status, @header, @body = @app.call(env) [@status, @header, self] end def close @body.close if @body.respond_to? :close end # By default, log to rack.errors. def <<(str) @env["rack.errors"].write(str) @env["rack.errors"].flush end def each length = 0 @body.each { |part| length += part.size yield part } @now = Time.now # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common # lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 - # %{%s - %s [%s] "%s %s%s %s" %d %s\n} % @logger << %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n} % [ @env['HTTP_X_FORWARDED_FOR'] || @env["REMOTE_ADDR"] || "-", @env["REMOTE_USER"] || "-", @now.strftime("%d/%b/%Y %H:%M:%S"), @env["REQUEST_METHOD"], @env["PATH_INFO"], @env["QUERY_STRING"].empty? ? "" : "?"+@env["QUERY_STRING"], @env["HTTP_VERSION"], @status.to_s[0..3], (length.zero? ? "-" : length.to_s), @now - @time ] end end end PKd9`rack/deflater.rbFrequire "zlib" require "stringio" module Rack class Deflater def initialize(app) @app = app end def call(env) status, headers, body = @app.call(env) request = Request.new(env) encoding = Utils.select_best_encoding(%w(gzip deflate identity), request.accept_encoding) case encoding when "gzip" mtime = headers["Last-Modified"] || Time.now [status, headers.merge("Content-Encoding" => "gzip"), self.class.gzip(body, mtime)] when "deflate" [status, headers.merge("Content-Encoding" => "deflate"), self.class.deflate(body)] when "identity" [status, headers, body] when nil message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found." [406, {"Content-Type" => "text/plain"}, message] end end def self.gzip(body, mtime) io = StringIO.new gzip = Zlib::GzipWriter.new(io) gzip.mtime = mtime # TODO: Add streaming body.each { |part| gzip << part } gzip.close return io.string end DEFLATE_ARGS = [ Zlib::DEFAULT_COMPRESSION, # drop the zlib header which causes both Safari and IE to choke -Zlib::MAX_WBITS, Zlib::DEF_MEM_LEVEL, Zlib::DEFAULT_STRATEGY ] # Loosely based on Mongrel's Deflate handler def self.deflate(body) deflater = Zlib::Deflate.new(*DEFLATE_ARGS) # TODO: Add streaming body.each { |part| deflater << part } return deflater.finish end end end PKd9HLAjerack/directory.rberequire 'time' module Rack # Rack::Directory serves entries below the +root+ given, according to the # path info of the Rack request. If a directory is found, the file's contents # will be presented in an html based index. If a file is found, the env will # be passed to the specified +app+. # # If +app+ is not specified, a Rack::File of the same +root+ will be used. class Directory DIR_FILE = "%s%s%s%s" DIR_PAGE = <<-PAGE %s

%s


%s
Name Size Type Last Modified

PAGE attr_reader :files attr_accessor :root, :path def initialize(root, app=nil) @root = root @app = app unless defined? @app @app = Rack::File.new(@root) end end def call(env) dup._call(env) end F = ::File def _call(env) if env["PATH_INFO"].include? ".." body = "Forbidden\n" size = body.respond_to?(:bytesize) ? body.bytesize : body.size return [403, {"Content-Type" => "text/plain","Content-Length" => size.to_s}, [body]] end @path = F.join(@root, Utils.unescape(env['PATH_INFO'])) if F.exist?(@path) and F.readable?(@path) if F.file?(@path) return @app.call(env) elsif F.directory?(@path) @files = [['../','Parent Directory','','','']] sName, pInfo = env.values_at('SCRIPT_NAME', 'PATH_INFO') Dir.entries(@path).sort.each do |file| next if file[0] == ?. fl = F.join(@path, file) sz = F.size(fl) url = F.join(sName, pInfo, file) type = F.directory?(fl) ? 'directory' : MIME_TYPES.fetch(F.extname(file)[1..-1],'unknown') size = (type!='directory' ? (sz<10240 ? "#{sz}B" : "#{sz/1024}KB") : '-') mtime = F.mtime(fl).httpdate @files << [ url, file, size, type, mtime ] end return [ 200, {'Content-Type'=>'text/html'}, self ] end end body = "Entity not found: #{env["PATH_INFO"]}\n" size = body.respond_to?(:bytesize) ? body.bytesize : body.size return [404, {"Content-Type" => "text/plain", "Content-Length" => size.to_s}, [body]] end def each show_path = @path.sub(/^#{@root}/,'') files = @files.map{|f| DIR_FILE % f }*"\n" page = DIR_PAGE % [ show_path, show_path , files ] page.each_line{|l| yield l } end def each_entry @files.each{|e| yield e } end # From WEBrick. MIME_TYPES = { "ai" => "application/postscript", "asc" => "text/plain", "avi" => "video/x-msvideo", "bin" => "application/octet-stream", "bmp" => "image/bmp", "class" => "application/octet-stream", "cer" => "application/pkix-cert", "crl" => "application/pkix-crl", "crt" => "application/x-x509-ca-cert", #"crl" => "application/x-pkcs7-crl", "css" => "text/css", "dms" => "application/octet-stream", "doc" => "application/msword", "dvi" => "application/x-dvi", "eps" => "application/postscript", "etx" => "text/x-setext", "exe" => "application/octet-stream", "gif" => "image/gif", "htm" => "text/html", "html" => "text/html", "jpe" => "image/jpeg", "jpeg" => "image/jpeg", "jpg" => "image/jpeg", "js" => "text/javascript", "lha" => "application/octet-stream", "lzh" => "application/octet-stream", "mov" => "video/quicktime", "mpe" => "video/mpeg", "mpeg" => "video/mpeg", "mpg" => "video/mpeg", "pbm" => "image/x-portable-bitmap", "pdf" => "application/pdf", "pgm" => "image/x-portable-graymap", "png" => "image/png", "pnm" => "image/x-portable-anymap", "ppm" => "image/x-portable-pixmap", "ppt" => "application/vnd.ms-powerpoint", "ps" => "application/postscript", "qt" => "video/quicktime", "ras" => "image/x-cmu-raster", "rb" => "text/plain", "rd" => "text/plain", "rtf" => "application/rtf", "sgm" => "text/sgml", "sgml" => "text/sgml", "tif" => "image/tiff", "tiff" => "image/tiff", "txt" => "text/plain", "xbm" => "image/x-xbitmap", "xls" => "application/vnd.ms-excel", "xml" => "text/xml", "xpm" => "image/x-xpixmap", "xwd" => "image/x-xwindowdump", "zip" => "application/zip", } end end PKd9Q $_ rack/file.rb #require 'time' module Rack # Rack::File serves files below the +root+ given, according to the # path info of the Rack request. # # Handlers can detect if bodies are a Rack::File, and use mechanisms # like sendfile on the +path+. class File attr_accessor :root attr_accessor :path def initialize(root) @root = root end def call(env) dup._call(env) end F = ::File def _call(env) if env["PATH_INFO"].include? ".." body = "Forbidden\n" size = body.respond_to?(:bytesize) ? body.bytesize : body.size return [403, {"Content-Type" => "text/plain","Content-Length" => size.to_s}, [body]] end @path = F.join(@root, Utils.unescape(env["PATH_INFO"])) ext = F.extname(@path)[1..-1] if F.file?(@path) && F.readable?(@path) [200, { "Last-Modified" => F.mtime(@path).httpdate, "Content-Type" => MIME_TYPES[ext] || "text/plain", "Content-Length" => F.size(@path).to_s }, self] else body = "File not found: #{env["PATH_INFO"]}\n" size = body.respond_to?(:bytesize) ? body.bytesize : body.size [404, {"Content-Type" => "text/plain", "Content-Length" => size.to_s}, [body]] end end def each F.open(@path, "rb") { |file| while part = file.read(8192) yield part end } end # :stopdoc: # From WEBrick with some additions. MIME_TYPES = { "ai" => "application/postscript", "asc" => "text/plain", "avi" => "video/x-msvideo", "bin" => "application/octet-stream", "bmp" => "image/bmp", "class" => "application/octet-stream", "cer" => "application/pkix-cert", "crl" => "application/pkix-crl", "crt" => "application/x-x509-ca-cert", #"crl" => "application/x-pkcs7-crl", "css" => "text/css", "dms" => "application/octet-stream", "doc" => "application/msword", "dvi" => "application/x-dvi", "eps" => "application/postscript", "etx" => "text/x-setext", "exe" => "application/octet-stream", "gif" => "image/gif", "htm" => "text/html", "html" => "text/html", "jpe" => "image/jpeg", "jpeg" => "image/jpeg", "jpg" => "image/jpeg", "js" => "text/javascript", "lha" => "application/octet-stream", "lzh" => "application/octet-stream", "mov" => "video/quicktime", "mp3" => "audio/mpeg", "mpe" => "video/mpeg", "mpeg" => "video/mpeg", "mpg" => "video/mpeg", "pbm" => "image/x-portable-bitmap", "pdf" => "application/pdf", "pgm" => "image/x-portable-graymap", "png" => "image/png", "pnm" => "image/x-portable-anymap", "ppm" => "image/x-portable-pixmap", "ppt" => "application/vnd.ms-powerpoint", "ps" => "application/postscript", "qt" => "video/quicktime", "ras" => "image/x-cmu-raster", "rb" => "text/plain", "rd" => "text/plain", "rtf" => "application/rtf", "sgm" => "text/sgml", "sgml" => "text/sgml", "tif" => "image/tiff", "tiff" => "image/tiff", "txt" => "text/plain", "xbm" => "image/x-xbitmap", "xls" => "application/vnd.ms-excel", "xml" => "text/xml", "xpm" => "image/x-xpixmap", "xwd" => "image/x-xwindowdump", "zip" => "application/zip", } # :startdoc: end end PKd9 rack/handler/PKd92 SNrack/handler.rbNmodule Rack # *Handlers* connect web servers with Rack. # # Rack includes Handlers for Mongrel, WEBrick, FastCGI, CGI, SCGI # and LiteSpeed. # # Handlers usually are activated by calling MyHandler.run(myapp). # A second optional hash can be passed to include server-specific # configuration. module Handler def self.get(server) return unless server if klass = @handlers[server] obj = Object klass.split("::").each { |x| obj = obj.const_get(x) } obj else Rack::Handler.const_get(server.capitalize) end end def self.register(server, klass) @handlers ||= {} @handlers[server] = klass end autoload :CGI, "rack/handler/cgi" autoload :FastCGI, "rack/handler/fastcgi" autoload :Mongrel, "rack/handler/mongrel" autoload :EventedMongrel, "rack/handler/evented_mongrel" autoload :WEBrick, "rack/handler/webrick" autoload :LSWS, "rack/handler/lsws" autoload :SCGI, "rack/handler/scgi" register 'cgi', 'Rack::Handler::CGI' register 'fastcgi', 'Rack::Handler::FastCGI' register 'mongrel', 'Rack::Handler::Mongrel' register 'emongrel', 'Rack::Handler::EventedMongrel' register 'webrick', 'Rack::Handler::WEBrick' register 'lsws', 'Rack::Handler::LSWS' register 'scgi', 'Rack::Handler::SCGI' end end PKd95F;A; rack/lint.rbA;module Rack # Rack::Lint validates your application and the requests and # responses according to the Rack spec. class Lint def initialize(app) @app = app end # :stopdoc: class LintError < RuntimeError; end module Assertion def assert(message, &block) unless block.call raise LintError, message end end end include Assertion ## This specification aims to formalize the Rack protocol. You ## can (and should) use Rack::Lint to enforce it. ## ## When you develop middleware, be sure to add a Lint before and ## after to catch all mistakes. ## = Rack applications ## A Rack application is an Ruby object (not a class) that ## responds to +call+. def call(env=nil) dup._call(env) end def _call(env) ## It takes exactly one argument, the *environment* assert("No env given") { env } check_env env env['rack.input'] = InputWrapper.new(env['rack.input']) env['rack.errors'] = ErrorWrapper.new(env['rack.errors']) ## and returns an Array of exactly three values: status, headers, @body = @app.call(env) ## The *status*, check_status status ## the *headers*, check_headers headers ## and the *body*. check_content_type status, headers [status, headers, self] end ## == The Environment def check_env(env) ## The environment must be an true instance of Hash (no ## subclassing allowed) that includes CGI-like headers. ## The application is free to modify the environment. assert("env #{env.inspect} is not a Hash, but #{env.class}") { env.instance_of? Hash } ## ## The environment is required to include these variables ## (adopted from PEP333), except when they'd be empty, but see ## below. ## REQUEST_METHOD:: The HTTP request method, such as ## "GET" or "POST". This cannot ever ## be an empty string, and so is ## always required. ## SCRIPT_NAME:: The initial portion of the request ## URL's "path" that corresponds to the ## application object, so that the ## application knows its virtual ## "location". This may be an empty ## string, if the application corresponds ## to the "root" of the server. ## PATH_INFO:: The remainder of the request URL's ## "path", designating the virtual ## "location" of the request's target ## within the application. This may be an ## empty string, if the request URL targets ## the application root and does not have a ## trailing slash. ## QUERY_STRING:: The portion of the request URL that ## follows the ?, if any. May be ## empty, but is always required! ## SERVER_NAME, SERVER_PORT:: When combined with SCRIPT_NAME and PATH_INFO, these variables can be used to complete the URL. Note, however, that HTTP_HOST, if present, should be used in preference to SERVER_NAME for reconstructing the request URL. SERVER_NAME and SERVER_PORT can never be empty strings, and so are always required. ## HTTP_ Variables:: Variables corresponding to the ## client-supplied HTTP request ## headers (i.e., variables whose ## names begin with HTTP_). The ## presence or absence of these ## variables should correspond with ## the presence or absence of the ## appropriate HTTP header in the ## request. ## In addition to this, the Rack environment must include these ## Rack-specific variables: ## rack.version:: The Array [0,1], representing this version of Rack. ## rack.url_scheme:: +http+ or +https+, depending on the request URL. ## rack.input:: See below, the input stream. ## rack.errors:: See below, the error stream. ## rack.multithread:: true if the application object may be simultaneously invoked by another thread in the same process, false otherwise. ## rack.multiprocess:: true if an equivalent application object may be simultaneously invoked by another process, false otherwise. ## rack.run_once:: true if the server expects (but does not guarantee!) that the application will only be invoked this one time during the life of its containing process. Normally, this will only be true for a server based on CGI (or something similar). ## The server or the application can store their own data in the ## environment, too. The keys must contain at least one dot, ## and should be prefixed uniquely. The prefix rack. ## is reserved for use with the Rack core distribution and must ## not be used otherwise. ## %w[REQUEST_METHOD SERVER_NAME SERVER_PORT QUERY_STRING rack.version rack.input rack.errors rack.multithread rack.multiprocess rack.run_once].each { |header| assert("env missing required key #{header}") { env.include? header } } ## The environment must not contain the keys ## HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH ## (use the versions without HTTP_). %w[HTTP_CONTENT_TYPE HTTP_CONTENT_LENGTH].each { |header| assert("env contains #{header}, must use #{header[5,-1]}") { not env.include? header } } ## The CGI keys (named without a period) must have String values. env.each { |key, value| next if key.include? "." # Skip extensions assert("env variable #{key} has non-string value #{value.inspect}") { value.instance_of? String } } ## ## There are the following restrictions: ## * rack.version must be an array of Integers. assert("rack.version must be an Array, was #{env["rack.version"].class}") { env["rack.version"].instance_of? Array } ## * rack.url_scheme must either be +http+ or +https+. assert("rack.url_scheme unknown: #{env["rack.url_scheme"].inspect}") { %w[http https].include? env["rack.url_scheme"] } ## * There must be a valid input stream in rack.input. check_input env["rack.input"] ## * There must be a valid error stream in rack.errors. check_error env["rack.errors"] ## * The REQUEST_METHOD must be one of +GET+, +POST+, +PUT+, ## +DELETE+, +HEAD+, +OPTIONS+, +TRACE+. assert("REQUEST_METHOD unknown: #{env["REQUEST_METHOD"]}") { %w[GET POST PUT DELETE HEAD OPTIONS TRACE].include?(env["REQUEST_METHOD"]) } ## * The SCRIPT_NAME, if non-empty, must start with / assert("SCRIPT_NAME must start with /") { !env.include?("SCRIPT_NAME") || env["SCRIPT_NAME"] == "" || env["SCRIPT_NAME"] =~ /\A\// } ## * The PATH_INFO, if non-empty, must start with / assert("PATH_INFO must start with /") { !env.include?("PATH_INFO") || env["PATH_INFO"] == "" || env["PATH_INFO"] =~ /\A\// } ## * The CONTENT_LENGTH, if given, must consist of digits only. assert("Invalid CONTENT_LENGTH: #{env["CONTENT_LENGTH"]}") { !env.include?("CONTENT_LENGTH") || env["CONTENT_LENGTH"] =~ /\A\d+\z/ } ## * One of SCRIPT_NAME or PATH_INFO must be ## set. PATH_INFO should be / if ## SCRIPT_NAME is empty. assert("One of SCRIPT_NAME or PATH_INFO must be set (make PATH_INFO '/' if SCRIPT_NAME is empty)") { env["SCRIPT_NAME"] || env["PATH_INFO"] } ## SCRIPT_NAME never should be /, but instead be empty. assert("SCRIPT_NAME cannot be '/', make it '' and PATH_INFO '/'") { env["SCRIPT_NAME"] != "/" } end ## === The Input Stream def check_input(input) ## The input stream must respond to +gets+, +each+ and +read+. [:gets, :each, :read].each { |method| assert("rack.input #{input} does not respond to ##{method}") { input.respond_to? method } } end class InputWrapper include Assertion def initialize(input) @input = input end ## * +gets+ must be called without arguments and return a string, ## or +nil+ on EOF. def gets(*args) assert("rack.input#gets called with arguments") { args.size == 0 } v = @input.gets assert("rack.input#gets didn't return a String") { v.nil? or v.instance_of? String } v end ## * +read+ must be called without or with one integer argument ## and return a string, or +nil+ on EOF. def read(*args) assert("rack.input#read called with too many arguments") { args.size <= 1 } if args.size == 1 assert("rack.input#read called with non-integer argument") { args.first.kind_of? Integer } end v = @input.read(*args) assert("rack.input#read didn't return a String") { v.nil? or v.instance_of? String } v end ## * +each+ must be called without arguments and only yield Strings. def each(*args) assert("rack.input#each called with arguments") { args.size == 0 } @input.each { |line| assert("rack.input#each didn't yield a String") { line.instance_of? String } yield line } end ## * +close+ must never be called on the input stream. def close(*args) assert("rack.input#close must not be called") { false } end end ## === The Error Stream def check_error(error) ## The error stream must respond to +puts+, +write+ and +flush+. [:puts, :write, :flush].each { |method| assert("rack.error #{error} does not respond to ##{method}") { error.respond_to? method } } end class ErrorWrapper include Assertion def initialize(error) @error = error end ## * +puts+ must be called with a single argument that responds to +to_s+. def puts(str) @error.puts str end ## * +write+ must be called with a single argument that is a String. def write(str) assert("rack.errors#write not called with a String") { str.instance_of? String } @error.write str end ## * +flush+ must be called without arguments and must be called ## in order to make the error appear for sure. def flush @error.flush end ## * +close+ must never be called on the error stream. def close(*args) assert("rack.errors#close must not be called") { false } end end ## == The Response ## === The Status def check_status(status) ## The status, if parsed as integer (+to_i+), must be greater than or equal to 100. assert("Status must be >=100 seen as integer") { status.to_i >= 100 } end ## === The Headers def check_headers(header) ## The header must respond to each, and yield values of key and value. assert("headers object should respond to #each, but doesn't (got #{header.class} as headers)") { header.respond_to? :each } header.each { |key, value| ## The header keys must be Strings. assert("header key must be a string, was #{key.class}") { key.instance_of? String } ## The header must not contain a +Status+ key, assert("header must not contain Status") { key.downcase != "status" } ## contain keys with : or newlines in their name, assert("header names must not contain : or \\n") { key !~ /[:\n]/ } ## contain keys names that end in - or _, assert("header names must not end in - or _") { key !~ /[-_]\z/ } ## but only contain keys that consist of ## letters, digits, _ or - and start with a letter. assert("invalid header name: #{key}") { key =~ /\A[a-zA-Z][a-zA-Z0-9_-]*\z/ } ## ## The values of the header must respond to #each. assert("header values must respond to #each, but the value of " + "'#{key}' doesn't (is #{value.class})") { value.respond_to? :each } value.each { |item| ## The values passed on #each must be Strings assert("header values must consist of Strings, but '#{key}' also contains a #{item.class}") { item.instance_of?(String) } ## and not contain characters below 037. assert("invalid header value #{key}: #{item.inspect}") { item !~ /[\000-\037]/ } } } end ## === The Content-Type def check_content_type(status, headers) headers.each { |key, value| ## There must be a Content-Type, except when the ## +Status+ is 204 or 304, in which case there must be none ## given. if key.downcase == "content-type" assert("Content-Type header found in #{status} response, not allowed"){ not [204, 304].include? status.to_i } return end } assert("No Content-Type header found") { [204, 304].include? status.to_i } end ## === The Body def each @closed = false ## The Body must respond to #each @body.each { |part| ## and must only yield String values. assert("Body yielded non-string value #{part.inspect}") { part.instance_of? String } yield part } ## ## If the Body responds to #close, it will be called after iteration. # XXX howto: assert("Body has not been closed") { @closed } ## ## The Body commonly is an Array of Strings, the application ## instance itself, or a File-like object. end def close @closed = true @body.close if @body.respond_to?(:close) end # :startdoc: end end ## == Thanks ## Some parts of this specification are adopted from PEP333: Python ## Web Server Gateway Interface ## v1.0 (http://www.python.org/dev/peps/pep-0333/). I'd like to thank ## everyone involved in that effort. PKd9brack/lobster.rbrequire 'zlib' require 'rack/request' require 'rack/response' module Rack # Paste has a Pony, Rack has a Lobster! class Lobster LobsterString = Zlib::Inflate.inflate("eJx9kEEOwyAMBO99xd7MAcytUhPlJyj2 P6jy9i4k9EQyGAnBarEXeCBqSkntNXsi/ZCvC48zGQoZKikGrFMZvgS5ZHd+aGWVuWwhVF0 t1drVmiR42HcWNz5w3QanT+2gIvTVCiE1lm1Y0eU4JGmIIbaKwextKn8rvW+p5PIwFl8ZWJ I8jyiTlhTcYXkekJAzTyYN6E08A+dk8voBkAVTJQ==".delete("\n ").unpack("m*")[0]) LambdaLobster = lambda { |env| if env["QUERY_STRING"].include?("flip") lobster = LobsterString.split("\n"). map { |line| line.ljust(42).reverse }. join("\n") href = "?" else lobster = LobsterString href = "?flip" end [200, {"Content-Type" => "text/html"}, ["Lobstericious!", "
", lobster, "
", "flip!"] ] } def call(env) req = Request.new(env) if req.GET["flip"] == "left" lobster = LobsterString.split("\n"). map { |line| line.ljust(42).reverse }. join("\n") href = "?flip=right" elsif req.GET["flip"] == "crash" raise "Lobster crashed" else lobster = LobsterString href = "?flip=left" end Response.new.finish do |res| res.write "Lobstericious!" res.write "
"
        res.write lobster
        res.write "
" res.write "

flip!

" res.write "

crash!

" end end end end if $0 == __FILE__ require 'rack' require 'rack/showexceptions' Rack::Handler::WEBrick.run \ Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)), :Port => 9292 end PKd9D d rack/mock.rb]require 'uri' require 'stringio' require 'rack/lint' require 'rack/utils' require 'rack/response' module Rack # Rack::MockRequest helps testing your Rack application without # actually using HTTP. # # After performing a request on a URL with get/post/put/delete, it # returns a MockResponse with useful helper methods for effective # testing. # # You can pass a hash with additional configuration to the # get/post/put/delete. # :input:: A String or IO-like to be used as rack.input. # :fatal:: Raise a FatalWarning if the app writes to rack.errors. # :lint:: If true, wrap the application in a Rack::Lint. class MockRequest class FatalWarning < RuntimeError end class FatalWarner def puts(warning) raise FatalWarning, warning end def write(warning) raise FatalWarning, warning end def flush end def string "" end end DEFAULT_ENV = { "rack.version" => [0,1], "rack.input" => StringIO.new, "rack.errors" => StringIO.new, "rack.multithread" => true, "rack.multiprocess" => true, "rack.run_once" => false, } def initialize(app) @app = app end def get(uri, opts={}) request("GET", uri, opts) end def post(uri, opts={}) request("POST", uri, opts) end def put(uri, opts={}) request("PUT", uri, opts) end def delete(uri, opts={}) request("DELETE", uri, opts) end def request(method="GET", uri="", opts={}) env = self.class.env_for(uri, opts.merge(:method => method)) if opts[:lint] app = Rack::Lint.new(@app) else app = @app end errors = env["rack.errors"] MockResponse.new(*(app.call(env) + [errors])) end # Return the Rack environment used for a request to +uri+. def self.env_for(uri="", opts={}) uri = URI(uri) env = DEFAULT_ENV.dup env["REQUEST_METHOD"] = opts[:method] || "GET" env["SERVER_NAME"] = uri.host || "example.org" env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80" env["QUERY_STRING"] = uri.query.to_s env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path env["rack.url_scheme"] = uri.scheme || "http" env["SCRIPT_NAME"] = opts[:script_name] || "" if opts[:fatal] env["rack.errors"] = FatalWarner.new else env["rack.errors"] = StringIO.new end opts[:input] ||= "" if String === opts[:input] env["rack.input"] = StringIO.new(opts[:input]) else env["rack.input"] = opts[:input] end opts.each { |field, value| env[field] = value if String === field } env end end # Rack::MockResponse provides useful helpers for testing your apps. # Usually, you don't create the MockResponse on your own, but use # MockRequest. class MockResponse def initialize(status, headers, body, errors=StringIO.new("")) @status = status.to_i @original_headers = headers @headers = Rack::Utils::HeaderHash.new headers.each { |field, values| values.each { |value| @headers[field] = value } @headers[field] = "" if values.empty? } @body = "" body.each { |part| @body << part } @errors = errors.string end # Status attr_reader :status # Headers attr_reader :headers, :original_headers def [](field) headers[field] end # Body attr_reader :body def =~(other) @body =~ other end def match(other) @body.match other end # Errors attr_accessor :errors include Response::Helpers end end PKd9yN<rack/recursive.rbOrequire 'uri' module Rack # Rack::ForwardRequest gets caught by Rack::Recursive and redirects # the current request to the app at +url+. # # raise ForwardRequest.new("/not-found") # class ForwardRequest < Exception attr_reader :url, :env def initialize(url, env={}) @url = URI(url) @env = env @env["PATH_INFO"] = @url.path @env["QUERY_STRING"] = @url.query if @url.query @env["HTTP_HOST"] = @url.host if @url.host @env["HTTP_PORT"] = @url.port if @url.port @env["rack.url_scheme"] = @url.scheme if @url.scheme super "forwarding to #{url}" end end # Rack::Recursive allows applications called down the chain to # include data from other applications (by using # rack['rack.recursive.include'][...] or raise a # ForwardRequest to redirect internally. class Recursive def initialize(app) @app = app end def call(env) @script_name = env["SCRIPT_NAME"] @app.call(env.merge('rack.recursive.include' => method(:include))) rescue ForwardRequest => req call(env.merge(req.env)) end def include(env, path) unless path.index(@script_name) == 0 && (path[@script_name.size] == ?/ || path[@script_name.size].nil?) raise ArgumentError, "can only include below #{@script_name}, not #{path}" end env = env.merge("PATH_INFO" => path, "SCRIPT_NAME" => @script_name, "REQUEST_METHOD" => "GET", "CONTENT_LENGTH" => "0", "CONTENT_TYPE" => "", "rack.input" => StringIO.new("")) @app.call(env) end end end PKd9.rack/reloader.rb require 'thread' module Rack # Rack::Reloader checks on every request, but at most every +secs+ # seconds, if a file loaded changed, and reloads it, logging to # rack.errors. # # It is recommended you use ShowExceptions to catch SyntaxErrors etc. class Reloader def initialize(app, secs=10) @app = app @secs = secs # reload every @secs seconds max @last = Time.now end def call(env) if Time.now > @last + @secs Thread.exclusive { reload!(env['rack.errors']) @last = Time.now } end @app.call(env) end def reload!(stderr=STDERR) need_reload = $LOADED_FEATURES.find_all { |loaded| begin if loaded =~ /\A[.\/]/ # absolute filename or 1.9 abs = loaded else abs = $LOAD_PATH.map { |path| ::File.join(path, loaded) }. find { |file| ::File.exist? file } end if abs ::File.mtime(abs) > @last - @secs rescue false else false end end } need_reload.each { |l| $LOADED_FEATURES.delete l } need_reload.each { |to_load| begin if require to_load stderr.puts "#{self.class}: reloaded `#{to_load}'" end rescue LoadError, SyntaxError => e raise e # Possibly ShowExceptions end } stderr.flush need_reload end end end PKd9rrack/request.rbrequire 'rack/utils' module Rack # Rack::Request provides a convenient interface to a Rack # environment. It is stateless, the environment +env+ passed to the # constructor will be directly modified. # # req = Rack::Request.new(env) # req.post? # req.params["data"] class Request # The environment of the request. attr_reader :env def initialize(env) @env = env end def body; @env["rack.input"] end def scheme; @env["rack.url_scheme"] end def script_name; @env["SCRIPT_NAME"].to_s end def path_info; @env["PATH_INFO"].to_s end def port; @env["SERVER_PORT"].to_i end def request_method; @env["REQUEST_METHOD"] end def query_string; @env["QUERY_STRING"].to_s end def content_length; @env['CONTENT_LENGTH'] end def content_type; @env['CONTENT_TYPE'] end # The media type (type/subtype) portion of the CONTENT_TYPE header # without any media type parameters. e.g., when CONTENT_TYPE is # "text/plain;charset=utf-8", the media-type is "text/plain". # # For more information on the use of media types in HTTP, see: # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 def media_type content_type && content_type.split(/\s*[;,]\s*/, 2)[0].downcase end # The media type parameters provided in CONTENT_TYPE as a Hash, or # an empty Hash if no CONTENT_TYPE or media-type parameters were # provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8", # this method responds with the following Hash: # { 'charset' => 'utf-8' } def media_type_params return {} if content_type.nil? content_type.split(/\s*[;,]\s*/)[1..-1]. collect { |s| s.split('=', 2) }. inject({}) { |hash,(k,v)| hash[k.downcase] = v ; hash } end # The character set of the request body if a "charset" media type # parameter was given, or nil if no "charset" was specified. Note # that, per RFC2616, text/* media types that specify no explicit # charset are to be considered ISO-8859-1. def content_charset media_type_params['charset'] end def host # Remove port number. (@env["HTTP_HOST"] || @env["SERVER_NAME"]).gsub(/:\d+\z/, '') end def script_name=(s); @env["SCRIPT_NAME"] = s.to_s end def path_info=(s); @env["PATH_INFO"] = s.to_s end def get?; request_method == "GET" end def post?; request_method == "POST" end def put?; request_method == "PUT" end def delete?; request_method == "DELETE" end def head?; request_method == "HEAD" end # The set of form-data media-types. Requests that do not indicate # one of the media types presents in this list will not be eligible # for form-data / param parsing. FORM_DATA_MEDIA_TYPES = [ nil, 'application/x-www-form-urlencoded', 'multipart/form-data' ] # Determine whether the request body contains form-data by checking # the request media_type against registered form-data media-types: # "application/x-www-form-urlencoded" and "multipart/form-data". The # list of form-data media types can be modified through the # +FORM_DATA_MEDIA_TYPES+ array. def form_data? FORM_DATA_MEDIA_TYPES.include?(media_type) end # Returns the data recieved in the query string. def GET if @env["rack.request.query_string"] == query_string @env["rack.request.query_hash"] else @env["rack.request.query_string"] = query_string @env["rack.request.query_hash"] = Utils.parse_query(query_string) end end # Returns the data recieved in the request body. # # This method support both application/x-www-form-urlencoded and # multipart/form-data. def POST if @env["rack.request.form_input"].eql? @env["rack.input"] @env["rack.request.form_hash"] elsif form_data? @env["rack.request.form_input"] = @env["rack.input"] unless @env["rack.request.form_hash"] = Utils::Multipart.parse_multipart(env) @env["rack.request.form_vars"] = @env["rack.input"].read @env["rack.request.form_hash"] = Utils.parse_query(@env["rack.request.form_vars"]) end @env["rack.request.form_hash"] else {} end end # The union of GET and POST data. def params self.GET.update(self.POST) rescue EOFError => e self.GET end # shortcut for request.params[key] def [](key) params[key.to_s] end # shortcut for request.params[key] = value def []=(key, value) params[key.to_s] = value end # like Hash#values_at def values_at(*keys) keys.map{|key| params[key] } end # the referer of the client or '/' def referer @env['HTTP_REFERER'] || '/' end alias referrer referer def cookies return {} unless @env["HTTP_COOKIE"] if @env["rack.request.cookie_string"] == @env["HTTP_COOKIE"] @env["rack.request.cookie_hash"] else @env["rack.request.cookie_string"] = @env["HTTP_COOKIE"] # According to RFC 2109: # If multiple cookies satisfy the criteria above, they are ordered in # the Cookie header such that those with more specific Path attributes # precede those with less specific. Ordering with respect to other # attributes (e.g., Domain) is unspecified. @env["rack.request.cookie_hash"] = Utils.parse_query(@env["rack.request.cookie_string"], ';,').inject({}) {|h,(k,v)| h[k] = Array === v ? v.first : v h } end end def xhr? @env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" end # Tries to return a remake of the original request URL as a string. def url url = scheme + "://" url << host if scheme == "https" && port != 443 || scheme == "http" && port != 80 url << ":#{port}" end url << fullpath url end def fullpath path = script_name + path_info path << "?" << query_string unless query_string.empty? path end def accept_encoding @env["HTTP_ACCEPT_ENCODING"].to_s.split(/,\s*/).map do |part| m = /^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$/.match(part) # From WEBrick if m [m[1], (m[2] || 1.0).to_f] else raise "Invalid value for Accept-Encoding: #{part.inspect}" end end end end end PKd9@h?:rack/response.rb:require 'rack/request' require 'rack/utils' module Rack # Rack::Response provides a convenient interface to create a Rack # response. # # It allows setting of headers and cookies, and provides useful # defaults (a OK response containing HTML). # # You can use Response#write to iteratively generate your response, # but note that this is buffered by Rack::Response until you call # +finish+. +finish+ however can take a block inside which calls to # +write+ are syncronous with the Rack response. # # Your application's +call+ should end returning Response#finish. class Response def initialize(body=[], status=200, header={}, &block) @status = status @header = Utils::HeaderHash.new({"Content-Type" => "text/html"}. merge(header)) @writer = lambda { |x| @body << x } @block = nil @body = [] if body.respond_to? :to_str write body.to_str elsif body.respond_to?(:each) body.each { |part| write part.to_s } else raise TypeError, "stringable or iterable required" end yield self if block_given? end attr_reader :header attr_accessor :status, :body def [](key) header[key] end def []=(key, value) header[key] = value end def set_cookie(key, value) case value when Hash domain = "; domain=" + value[:domain] if value[:domain] path = "; path=" + value[:path] if value[:path] # According to RFC 2109, we need dashes here. # N.B.: cgi.rb uses spaces... expires = "; expires=" + value[:expires].clone.gmtime. strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires] value = value[:value] end value = [value] unless Array === value cookie = Utils.escape(key) + "=" + value.map { |v| Utils.escape v }.join("&") + "#{domain}#{path}#{expires}" case self["Set-Cookie"] when Array self["Set-Cookie"] << cookie when String self["Set-Cookie"] = [self["Set-Cookie"], cookie] when nil self["Set-Cookie"] = cookie end end def delete_cookie(key, value={}) unless Array === self["Set-Cookie"] self["Set-Cookie"] = [self["Set-Cookie"]].compact end self["Set-Cookie"].reject! { |cookie| cookie =~ /\A#{Utils.escape(key)}=/ } set_cookie(key, {:value => '', :path => nil, :domain => nil, :expires => Time.at(0) }.merge(value)) end def finish(&block) @block = block if [204, 304].include?(status.to_i) header.delete "Content-Type" [status.to_i, header.to_hash, []] else [status.to_i, header.to_hash, self] end end alias to_a finish # For *response def each(&callback) @body.each(&callback) @writer = callback @block.call(self) if @block end def write(str) @writer.call str.to_s str end def close body.close if body.respond_to?(:close) end def empty? @block == nil && @body.empty? end alias headers header module Helpers def invalid?; @status < 100 || @status >= 600; end def informational?; @status >= 100 && @status < 200; end def successful?; @status >= 200 && @status < 300; end def redirection?; @status >= 300 && @status < 400; end def client_error?; @status >= 400 && @status < 500; end def server_error?; @status >= 500 && @status < 600; end def ok?; @status == 200; end def forbidden?; @status == 403; end def not_found?; @status == 404; end def redirect?; [301, 302, 303, 307].include? @status; end def empty?; [201, 204, 304].include? @status; end # Headers attr_reader :headers, :original_headers def include?(header) !!headers[header] end def content_type headers["Content-Type"] end def content_length cl = headers["Content-Length"] cl ? cl.to_i : cl end def location headers["Location"] end end include Helpers end end PKd9 rack/session/PKd9+**rack/showexceptions.rb*Qrequire 'ostruct' require 'erb' require 'rack/request' module Rack # Rack::ShowExceptions catches all exceptions raised from the app it # wraps. It shows a useful backtrace with the sourcefile and # clickable context, the whole Rack environment and the request # data. # # Be careful when you use this on public-facing sites as it could # reveal information helpful to attackers. class ShowExceptions CONTEXT = 7 def initialize(app) @app = app @template = ERB.new(TEMPLATE) end def call(env) @app.call(env) rescue StandardError, LoadError, SyntaxError => e [500, {"Content-Type" => "text/html"}, pretty(env, e)] end def pretty(env, exception) req = Rack::Request.new(env) path = (req.script_name + req.path_info).squeeze("/") frames = exception.backtrace.map { |line| frame = OpenStruct.new if line =~ /(.*?):(\d+)(:in `(.*)')?/ frame.filename = $1 frame.lineno = $2.to_i frame.function = $4 begin lineno = frame.lineno-1 lines = ::File.readlines(frame.filename) frame.pre_context_lineno = [lineno-CONTEXT, 0].max frame.pre_context = lines[frame.pre_context_lineno...lineno] frame.context_line = lines[lineno].chomp frame.post_context_lineno = [lineno+CONTEXT, lines.size].min frame.post_context = lines[lineno+1..frame.post_context_lineno] rescue end frame else nil end }.compact env["rack.errors"].puts "#{exception.class}: #{exception.message}" env["rack.errors"].puts exception.backtrace.map { |l| "\t" + l } env["rack.errors"].flush [@template.result(binding)] end def h(obj) # :nodoc: case obj when String Utils.escape_html(obj) else Utils.escape_html(obj.inspect) end end # :stopdoc: # adapted from Django # Copyright (c) 2005, the Lawrence Journal-World # Used under the modified BSD license: # http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 TEMPLATE = <<'HTML' <%=h exception.class %> at <%=h path %>

<%=h exception.class %> at <%=h path %>

<%=h exception.message %>

Ruby <%=h frames.first.filename %>: in <%=h frames.first.function %>, line <%=h frames.first.lineno %>
Web <%=h req.request_method %> <%=h(req.host + path)%>

Jump to:

Traceback (innermost first)

    <% frames.each { |frame| %>
  • <%=h frame.filename %>: in <%=h frame.function %> <% if frame.context_line %>
    <% if frame.pre_context %>
      <% frame.pre_context.each { |line| %>
    1. <%=h line %>
    2. <% } %>
    <% end %>
    1. <%=h frame.context_line %>...
    <% if frame.post_context %>
      <% frame.post_context.each { |line| %>
    1. <%=h line %>
    2. <% } %>
    <% end %>
    <% end %>
  • <% } %>

Request information

GET

<% unless req.GET.empty? %> <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %> <% } %>
Variable Value
<%=h key %>
<%=h val.inspect %>
<% else %>

No GET data.

<% end %>

POST

<% unless req.POST.empty? %> <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %> <% } %>
Variable Value
<%=h key %>
<%=h val.inspect %>
<% else %>

No POST data.

<% end %> <% unless req.cookies.empty? %> <% req.cookies.each { |key, val| %> <% } %>
Variable Value
<%=h key %>
<%=h val.inspect %>
<% else %>

No cookie data.

<% end %>

Rack ENV

<% env.sort_by { |k, v| k.to_s }.each { |key, val| %> <% } %>
Variable Value
<%=h key %>
<%=h val %>

You're seeing this error because you use Rack::ShowException.

HTML # :startdoc: end end PKd9~ y rack/showstatus.rby require 'erb' require 'rack/request' require 'rack/utils' module Rack # Rack::ShowStatus catches all empty responses the app it wraps and # replaces them with a site explaining the error. # # Additional details can be put into rack.showstatus.detail # and will be shown as HTML. If such details exist, the error page # is always rendered, even if the reply was not empty. class ShowStatus def initialize(app) @app = app @template = ERB.new(TEMPLATE) end def call(env) status, headers, body = @app.call(env) # client or server error, or explicit message if status.to_i >= 400 && (body.empty? rescue false) || env["rack.showstatus.detail"] req = Rack::Request.new(env) message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s detail = env["rack.showstatus.detail"] || message body = @template.result(binding) size = body.respond_to?(:bytesize) ? body.bytesize : body.size [status, headers.merge("Content-Type" => "text/html", "Content-Length" => size.to_s), [body]] else [status, headers, body] end end def h(obj) # :nodoc: case obj when String Utils.escape_html(obj) else Utils.escape_html(obj.inspect) end end # :stopdoc: # adapted from Django # Copyright (c) 2005, the Lawrence Journal-World # Used under the modified BSD license: # http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 TEMPLATE = <<'HTML' <%=h message %> at <%=h req.script_name + req.path_info %>

<%=h message %> (<%= status.to_i %>)

Request Method: <%=h req.request_method %>
Request URL: <%=h req.url %>

<%= detail %>

You're seeing this error because you use Rack::ShowStatus.

HTML # :startdoc: end end PKd9cbrack/static.rbtmodule Rack # The Rack::Static middleware intercepts requests for static files # (javascript files, images, stylesheets, etc) based on the url prefixes # passed in the options, and serves them using a Rack::File object. This # allows a Rack stack to serve both static and dynamic content. # # Examples: # use Rack::Static, :urls => ["/media"] # will serve all requests beginning with /media from the "media" folder # located in the current directory (ie media/*). # # use Rack::Static, :urls => ["/css", "/images"], :root => "public" # will serve all requests beginning with /css or /images from the folder # "public" in the current directory (ie public/css/* and public/images/*) class Static def initialize(app, options={}) @app = app @urls = options[:urls] || ["/favicon.ico"] root = options[:root] || Dir.pwd @file_server = Rack::File.new(root) end def call(env) path = env["PATH_INFO"] can_serve = @urls.any? { |url| path.index(url) == 0 } if can_serve @file_server.call(env) else @app.call(env) end end end end PKd91rack/urlmap.rbRmodule Rack # Rack::URLMap takes a hash mapping urls or paths to apps, and # dispatches accordingly. Support for HTTP/1.1 host names exists if # the URLs start with http:// or https://. # # URLMap modifies the SCRIPT_NAME and PATH_INFO such that the part # relevant for dispatch is in the SCRIPT_NAME, and the rest in the # PATH_INFO. This should be taken care of when you need to # reconstruct the URL in order to create links. # # URLMap dispatches in such a way that the longest paths are tried # first, since they are most specific. class URLMap def initialize(map) @mapping = map.map { |location, app| if location =~ %r{\Ahttps?://(.*?)(/.*)} host, location = $1, $2 else host = nil end unless location[0] == ?/ raise ArgumentError, "paths need to start with /" end location = location.chomp('/') [host, location, app] }.sort_by { |(h, l, a)| -l.size } # Longest path first end def call(env) path = env["PATH_INFO"].to_s.squeeze("/") hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT') @mapping.each { |host, location, app| next unless (hHost == host || sName == host \ || (host.nil? && (hHost == sName || hHost == sName+':'+sPort))) next unless location == path[0, location.size] next unless path[location.size] == nil || path[location.size] == ?/ env["SCRIPT_NAME"] += location env["PATH_INFO"] = path[location.size..-1] return app.call(env) } [404, {"Content-Type" => "text/plain"}, ["Not Found: #{path}"]] end end end PKd9> F&$!$ rack/utils.rb!$require 'tempfile' module Rack # Rack::Utils contains a grab-bag of useful methods for writing web # applications adopted from all kinds of Ruby libraries. module Utils # Performs URI escaping so that you can construct proper # query strings faster. Use this rather than the cgi.rb # version since it's faster. (Stolen from Camping). def escape(s) s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) { '%'+$1.unpack('H2'*$1.size).join('%').upcase }.tr(' ', '+') end module_function :escape # Unescapes a URI escaped string. (Stolen from Camping). def unescape(s) s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){ [$1.delete('%')].pack('H*') } end module_function :unescape # Stolen from Mongrel, with some small modifications: # Parses a query string by breaking it up at the '&' # and ';' characters. You can also use this to parse # cookies by changing the characters used in the second # parameter (which defaults to '&;'). def parse_query(qs, d = '&;') params = {} (qs || '').split(/[#{d}] */n).each do |p| k, v = unescape(p).split('=', 2) if cur = params[k] if cur.class == Array params[k] << v else params[k] = [cur, v] end else params[k] = v end end return params end module_function :parse_query def build_query(params) params.map { |k, v| if v.class == Array build_query(v.map { |x| [k, x] }) else escape(k) + "=" + escape(v) end }.join("&") end module_function :build_query # Escape ampersands, brackets and quotes to their HTML/XML entities. def escape_html(string) string.to_s.gsub("&", "&"). gsub("<", "<"). gsub(">", ">"). gsub("'", "'"). gsub('"', """) end module_function :escape_html def select_best_encoding(available_encodings, accept_encoding) # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html expanded_accept_encoding = accept_encoding.map { |m, q| if m == "*" (available_encodings - accept_encoding.map { |m2, _| m2 }).map { |m2| [m2, q] } else [[m, q]] end }.inject([]) { |mem, list| mem + list } encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map { |m, _| m } unless encoding_candidates.include?("identity") encoding_candidates.push("identity") end expanded_accept_encoding.find_all { |m, q| q == 0.0 }.each { |m, _| encoding_candidates.delete(m) } return (encoding_candidates & available_encodings)[0] end module_function :select_best_encoding # The recommended manner in which to implement a contexting application # is to define a method #context in which a new Context is instantiated. # # As a Context is a glorified block, it is highly recommended that you # define the contextual block within the application's operational scope. # This would typically the application as you're place into Rack's stack. # # class MyObject # ... # def context app # Rack::Utils::Context.new app do |env| # do_stuff # response = app.call(env) # do_more_stuff # end # end # ... # end # # mobj = MyObject.new # app = mobj.context other_app # Rack::Handler::Mongrel.new app class Context < Proc alias_method :old_inspect, :inspect attr_reader :for, :app def initialize app_f, app_r raise 'running context not provided' unless app_f raise 'running context does not respond to #context' unless app_f.respond_to? :context raise 'application context not provided' unless app_r raise 'application context does not respond to #call' unless app_r.respond_to? :call @for = app_f @app = app_r end def inspect "#{old_inspect} ==> #{@for.inspect} ==> #{@app.inspect}" end def context app_r raise 'new application context not provided' unless app_r raise 'new application context does not respond to #call' unless app_r.respond_to? :call @for.context app_r end def pretty_print pp pp.text old_inspect pp.nest 1 do pp.breakable pp.text '=for> ' pp.pp @for pp.breakable pp.text '=app> ' pp.pp @app end end end # A case-normalizing Hash, adjusting on [] and []=. class HeaderHash < Hash def initialize(hash={}) hash.each { |k, v| self[k] = v } end def to_hash {}.replace(self) end def [](k) super capitalize(k) end def []=(k, v) super capitalize(k), v end def capitalize(k) k.to_s.downcase.gsub(/^.|[-_\s]./) { |x| x.upcase } end end # Every standard HTTP code mapped to the appropriate message. # Stolen from Mongrel. HTTP_STATUS_CODES = { 100 => 'Continue', 101 => 'Switching Protocols', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Moved Temporarily', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported' } # A multipart form data parser, adapted from IOWA. # # Usually, Rack::Request#POST takes care of calling this. module Multipart EOL = "\r\n" def self.parse_multipart(env) unless env['CONTENT_TYPE'] =~ %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n nil else boundary = "--#{$1}" params = {} buf = "" content_length = env['CONTENT_LENGTH'].to_i input = env['rack.input'] boundary_size = boundary.size + EOL.size bufsize = 16384 content_length -= boundary_size status = input.read(boundary_size) raise EOFError, "bad content body" unless status == boundary + EOL rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/ loop { head = nil body = '' filename = content_type = name = nil until head && buf =~ rx if !head && i = buf.index("\r\n\r\n") head = buf.slice!(0, i+2) # First \r\n buf.slice!(0, 2) # Second \r\n filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] content_type = head[/Content-Type: (.*)\r\n/ni, 1] name = head[/Content-Disposition:.* name="?([^\";]*)"?/ni, 1] if filename body = Tempfile.new("RackMultipart") body.binmode if body.respond_to?(:binmode) end next end # Save the read body part. if head && (boundary_size+4 < buf.size) body << buf.slice!(0, buf.size - (boundary_size+4)) end c = input.read(bufsize < content_length ? bufsize : content_length) raise EOFError, "bad content body" if c.nil? || c.empty? buf << c content_length -= c.size end # Save the rest. if i = buf.index(rx) body << buf.slice!(0, i) buf.slice!(0, boundary_size+2) content_length = -1 if $1 == "--" end if filename body.rewind data = {:filename => filename, :type => content_type, :name => name, :tempfile => body, :head => head} else data = body end if name if name =~ /\[\]\z/ params[name] ||= [] params[name] << data else params[name] = data end end break if buf.empty? || content_length == -1 } params end end end end end PKd9{J6rack/adapter/camping.rb#module Rack module Adapter class Camping def initialize(app) @app = app end def call(env) env["PATH_INFO"] ||= "" env["SCRIPT_NAME"] ||= "" controller = @app.run(env['rack.input'], env) h = controller.headers h.each_pair do |k,v| if v.kind_of? URI h[k] = v.to_s end end [controller.status, controller.headers, controller.body] end end end end PKd9'urack/adapter/rails.rbwrequire 'cgi' require 'jruby/rack/rails' # Based on http://github.com/macournoyer/thin/tree/master/lib/rack/adapter/rails.rb # Adapter to run a Rails app with any supported Rack handler. # By default it will try to load the Rails application in the # current directory in the development environment. # Options: # root: Root directory of the Rails app # env: Rails environment to run in (development, production or test) # Based on http://fuzed.rubyforge.org/ Rails adapter module Rack module Adapter class Rails def initialize(options={}) @root = options[:root] || Dir.pwd @env = options[:environment] || 'production' @public = options[:public] || ::File.join(@root, "public") @file_server = Rack::File.new(@public) end # TODO refactor this in File#can_serve?(path) ?? def file_exist?(path) full_path = ::File.join(@file_server.root, Utils.unescape(path)) ::File.file?(full_path) && ::File.readable?(full_path) end def serve_file(env) @file_server.call(env) end def serve_rails(env) request = Request.new(env) response = Response.new cgi = CGIWrapper.new(request, response) Dispatcher.dispatch(cgi, session_options(env), response) response.finish end def call(env) if env['rack.dynamic.requests.only'] serve_rails(env) else path = env['PATH_INFO'].chomp('/') cached_path = (path.empty? ? 'index' : path) + ActionController::Base.page_cache_extension if file_exist?(path) # Serve the file if it's there serve_file(env) elsif file_exist?(cached_path) # Serve the page cache if it's there env['PATH_INFO'] = cached_path serve_file(env) else # No static file, let Rails handle it serve_rails(env) end end end def session_options(env) env['rails.session_options'] || ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS end protected class CGIWrapper < ::CGI def initialize(request, response, *args) @request = request @response = response @args = *args @input = request.body super(*args) end def header(options = "text/html") if options.is_a?(String) @response['Content-Type'] = options unless @response['Content-Type'] else @response['Content-Length'] = options.delete('Content-Length').to_s if options['Content-Length'] @response['Content-Type'] = options.delete('type') || "text/html" @response['Content-Type'] += "; charset=" + options.delete('charset') if options['charset'] @response['Content-Language'] = options.delete('language') if options['language'] @response['Expires'] = options.delete('expires') if options['expires'] @response.status = options.delete('Status') if options['Status'] # Convert 'cookie' header to 'Set-Cookie' headers. # Because Set-Cookie header can appear more the once in the response body, # we store it in a line break seperated string that will be translated to # multiple Set-Cookie header by the handler. if cookie = options.delete('cookie') cookies = [] case cookie when Array then cookie.each { |c| cookies << c.to_s } when Hash then cookie.each { |_, c| cookies << c.to_s } else cookies << cookie.to_s end @output_cookies.each { |c| cookies << c.to_s } if @output_cookies @response['Set-Cookie'] = cookies unless cookies.empty? end options.each { |k,v| @response[k] = v } end "" end def params @params ||= @request.params end def cookies @request.cookies end def query_string @request.query_string end # Used to wrap the normal args variable used inside CGI. def args @args end # Used to wrap the normal env_table variable used inside CGI. def env_table @request.env end # Used to wrap the normal stdinput variable used inside CGI. def stdinput @input end def stdoutput STDERR.puts "stdoutput should not be used." @response.body end end end end end PKd9rack/auth/abstract/PKd9Wrack/auth/basic.rb[require 'rack/auth/abstract/handler' require 'rack/auth/abstract/request' module Rack module Auth # Rack::Auth::Basic implements HTTP Basic Authentication, as per RFC 2617. # # Initialize with the Rack application that you want protecting, # and a block that checks if a username and password pair are valid. # # See also: example/protectedlobster.rb class Basic < AbstractHandler def call(env) auth = Basic::Request.new(env) return unauthorized unless auth.provided? return bad_request unless auth.basic? if valid?(auth) env['REMOTE_USER'] = auth.username return @app.call(env) end unauthorized end private def challenge 'Basic realm="%s"' % realm end def valid?(auth) @authenticator.call(*auth.credentials) end class Request < Auth::AbstractRequest def basic? :basic == scheme end def credentials @credentials ||= params.unpack("m*").first.split(/:/, 2) end def username credentials.first end end end end end PKd9rack/auth/digest/PKd9[>CCrack/auth/openid.rbC;# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net gem 'ruby-openid', '~> 2' if defined? Gem require 'rack/auth/abstract/handler' #rack require 'uri' #std require 'pp' #std require 'openid' #gem require 'openid/extension' #gem require 'openid/store/memory' #gem module Rack module Auth # Rack::Auth::OpenID provides a simple method for permitting # openid based logins. It requires the ruby-openid library from # janrain to operate, as well as a rack method of session management. # # The ruby-openid home page is at http://openidenabled.com/ruby-openid/. # # The OpenID specifications can be found at # http://openid.net/specs/openid-authentication-1_1.html # and # http://openid.net/specs/openid-authentication-2_0.html. Documentation # for published OpenID extensions and related topics can be found at # http://openid.net/developers/specs/. # # It is recommended to read through the OpenID spec, as well as # ruby-openid's documentation, to understand what exactly goes on. However # a setup as simple as the presented examples is enough to provide # functionality. # # This library strongly intends to utilize the OpenID 2.0 features of the # ruby-openid library, while maintaining OpenID 1.0 compatiblity. # # All responses from this rack application will be 303 redirects unless an # error occurs, with the exception of an authentication request requiring # an HTML form submission. # # NOTE: Extensions are not currently supported by this implimentation of # the OpenID rack application due to the complexity of the current # ruby-openid extension handling. # # NOTE: Due to the amount of data that this library stores in the # session, Rack::Session::Cookie may fault. class OpenID < AbstractHandler class NoSession < RuntimeError; end # Required for ruby-openid OIDStore = ::OpenID::Store::Memory.new HTML = '%s%s' # A Hash of options is taken as it's single initializing # argument. For example: # # simple_oid = OpenID.new('http://mysite.com/') # # return_oid = OpenID.new('http://mysite.com/', { # :return_to => 'http://mysite.com/openid' # }) # # page_oid = OpenID.new('http://mysite.com/', # :login_good => 'http://mysite.com/auth_good' # ) # # complex_oid = OpenID.new('http://mysite.com/', # :return_to => 'http://mysite.com/openid', # :login_good => 'http://mysite.com/user/preferences', # :auth_fail => [500, {'Content-Type'=>'text/plain'}, # 'Unable to negotiate with foreign server.'], # :immediate => true, # :extensions => { # ::OpenID::SReg => [['email'],['nickname']] # } # ) # # = Arguments # # The first argument is the realm, identifying the site they are trusting # with their identity. This is required. # # NOTE: In OpenID 1.x, the realm or trust_root is optional and the # return_to url is required. As this library strives tward ruby-openid # 2.0, and OpenID 2.0 compatibiliy, the realm is required and return_to # is optional. However, this implimentation is still backwards compatible # with OpenID 1.0 servers. # # The optional second argument is a hash of options. # # == Options # # :return_to defines the url to return to after the client # authenticates with the openid service provider. This url should point # to where Rack::Auth::OpenID is mounted. If :return_to is not # provided, :return_to will be the current url including all query # parameters. # # :session_key defines the key to the session hash in the env. # It defaults to 'rack.session'. # # :openid_param defines at what key in the request parameters to # find the identifier to resolve. As per the 2.0 spec, the default is # 'openid_identifier'. # # :immediate as true will make immediate type of requests the # default. See OpenID specification documentation. # # === URL options # # :login_good is the url to go to after the authentication # process has completed. # # :login_fail is the url to go to after the authentication # process has failed. # # :login_quit is the url to go to after the authentication # process # has been cancelled. # # === Response options # # :no_session should be a rack response to be returned if no or # an incompatible session is found. # # :auth_fail should be a rack response to be returned if an # OpenID::DiscoveryFailure occurs. This is typically due to being unable # to access the identity url or identity server. # # :error should be a rack response to return if any other # generic error would occur and options[:catch_errors] is true. # # === Extensions # # :extensions should be a hash of openid extension # implementations. The key should be the extension main module, the value # should be an array of arguments for extension::Request.new # # The hash is iterated over and passed to #add_extension for processing. # Please see #add_extension for further documentation. def initialize(realm, options={}) @realm = realm realm = URI(realm) if realm.path.empty? raise ArgumentError, "Invalid realm path: '#{realm.path}'" elsif not realm.absolute? raise ArgumentError, "Realm '#{@realm}' not absolute" end [:return_to, :login_good, :login_fail, :login_quit].each do |key| if options.key? key and luri = URI(options[key]) if !luri.absolute? raise ArgumentError, ":#{key} is not an absolute uri: '#{luri}'" end end end if options[:return_to] and ruri = URI(options[:return_to]) if ruri.path.empty? raise ArgumentError, "Invalid return_to path: '#{ruri.path}'" elsif realm.path != ruri.path[0, realm.path.size] raise ArgumentError, 'return_to not within realm.' \ end end # TODO: extension support if extensions = options.delete(:extensions) extensions.each do |ext, args| add_extension ext, *args end end @options = { :session_key => 'rack.session', :openid_param => 'openid_identifier', #:return_to, :login_good, :login_fail, :login_quit #:no_session, :auth_fail, :error :store => OIDStore, :immediate => false, :anonymous => false, :catch_errors => false }.merge(options) @extensions = {} end attr_reader :options, :extensions # It sets up and uses session data at :openid within the # session. It sets up the ::OpenID::Consumer using the store specified by # options[:store]. # # If the parameter specified by options[:openid_param] is # present, processing is passed to #check and the result is returned. # # If the parameter 'openid.mode' is set, implying a followup from the # openid server, processing is passed to #finish and the result is # returned. # # If neither of these conditions are met, a 400 error is returned. # # If an error is thrown and options[:catch_errors] is false, the # exception will be reraised. Otherwise a 500 error is returned. def call(env) env['rack.auth.openid'] = self session = env[@options[:session_key]] unless session and session.is_a? Hash raise(NoSession, 'No compatible session') end # let us work in our own namespace... session = (session[:openid] ||= {}) unless session and session.is_a? Hash raise(NoSession, 'Incompatible session') end request = Rack::Request.new env consumer = ::OpenID::Consumer.new session, @options[:store] if request.params['openid.mode'] finish consumer, session, request elsif request.params[@options[:openid_param]] check consumer, session, request else env['rack.errors'].puts "No valid params provided." bad_request end rescue NoSession env['rack.errors'].puts($!.message, *$@) @options. ### Missing or incompatible session fetch :no_session, [ 500, {'Content-Type'=>'text/plain'}, $!.message ] rescue env['rack.errors'].puts($!.message, *$@) if not @options[:catch_error] raise($!) end @options. fetch :error, [ 500, {'Content-Type'=>'text/plain'}, 'OpenID has encountered an error.' ] end # As the first part of OpenID consumer action, #check retrieves the data # required for completion. # # * session[:openid][:openid_param] is set to the submitted # identifier to be authenticated. # * session[:openid][:site_return] is set as the request's # HTTP_REFERER, unless already set. # * env['rack.auth.openid.request'] is the openid checkid # request instance. def check(consumer, session, req) session[:openid_param] = req.params[@options[:openid_param]] oid = consumer.begin(session[:openid_param], @options[:anonymous]) pp oid if $DEBUG req.env['rack.auth.openid.request'] = oid session[:site_return] ||= req.env['HTTP_REFERER'] # SETUP_NEEDED check! # see OpenID::Consumer::CheckIDRequest docs query_args = [@realm, *@options.values_at(:return_to, :immediate)] query_args[1] ||= req.url query_args[2] = false if session.key? :setup_needed pp query_args if $DEBUG ## Extension support extensions.each do |ext,args| oid.add_extension ext::Request.new(*args) end if oid.send_redirect?(*query_args) redirect = oid.redirect_url(*query_args) if $DEBUG pp redirect pp Rack::Utils.parse_query(URI(redirect).query) end [ 303, {'Location'=>redirect}, [] ] else # check on 'action' option. formbody = oid.form_markup(*query_args) if $DEBUG pp formbody end body = HTML % ['Confirm...', formbody] [ 200, {'Content-Type'=>'text/html'}, body.to_a ] end rescue ::OpenID::DiscoveryFailure => e # thrown from inside OpenID::Consumer#begin by yadis stuff req.env['rack.errors'].puts($!.message, *$@) @options. ### Foreign server failed fetch :auth_fail, [ 503, {'Content-Type'=>'text/plain'}, 'Foreign server failure.' ] end # This is the final portion of authentication. Unless any errors outside # of specification occur, a 303 redirect will be returned with Location # determined by the OpenID response type. If none of the response type # :login_* urls are set, the redirect will be set to # session[:openid][:site_return]. If # session[:openid][:site_return] is unset, the realm will be # used. # # Any messages from OpenID's response are appended to the 303 response # body. # # Data gathered from extensions are stored in session[:openid] with the # extension's namespace uri as the key. # # * env['rack.auth.openid.response'] is the openid response. # # The four valid possible outcomes are: # * failure: options[:login_fail] or # session[:site_return] or the realm # * session[:openid] is cleared and any messages are send to # rack.errors # * session[:openid]['authenticated'] is false # * success: options[:login_good] or # session[:site_return] or the realm # * session[:openid] is cleared # * session[:openid]['authenticated'] is true # * session[:openid]['identity'] is the actual identifier # * session[:openid]['identifier'] is the pretty identifier # * cancel: options[:login_good] or # session[:site_return] or the realm # * session[:openid] is cleared # * session[:openid]['authenticated'] is false # * setup_needed: resubmits the authentication request. A flag is set for # non-immediate handling. # * session[:openid][:setup_needed] is set to true, # which will prevent immediate style openid authentication. def finish(consumer, session, req) oid = consumer.complete(req.params, req.url) pp oid if $DEBUG req.env['rack.auth.openid.response'] = oid goto = session.fetch :site_return, @realm body = [] case oid.status when ::OpenID::Consumer::FAILURE session.clear session['authenticated'] = false req.env['rack.errors'].puts oid.message goto = @options[:login_fail] if @option.key? :login_fail body << "Authentication unsuccessful.\n" when ::OpenID::Consumer::SUCCESS session.clear ## Extension support extensions.each do |ext, args| session[ext::NS_URI] = ext::Response. from_success_response(oid). get_extension_args end session['authenticated'] = true # Value for unique identification and such session['identity'] = oid.identity_url # Value for display and UI labels session['identifier'] = oid.display_identifier goto = @options[:login_good] if @options.key? :login_good body << "Authentication successful.\n" when ::OpenID::Consumer::CANCEL session.clear session['authenticated'] = false goto = @options[:login_fail] if @option.key? :login_fail body << "Authentication cancelled.\n" when ::OpenID::Consumer::SETUP_NEEDED session[:setup_needed] = true unless o_id = session[:openid_param] raise('Required values missing.') end goto = req.script_name+ '?'+@options[:openid_param]+ '='+o_id body << "Reauthentication required.\n" end body << oid.message if oid.message [ 303, {'Location'=>goto}, body] end # The first argument should be the main extension module. # The extension module should contain the constants: # * class Request, with OpenID::Extension as an ancestor # * class Response, with OpenID::Extension as an ancestor # * string NS_URI, which defines the namespace of the extension, should # be an absolute http uri # # All trailing arguments will be passed to extension::Request.new in # #check. # The openid response will be passed to # extension::Response#from_success_response, #get_extension_args will be # called on the result to attain the gathered data. # # This method returns the key at which the response data will be found in # the session, which is the namespace uri by default. def add_extension ext, *args if not ext.is_a? Module raise TypeError, "#{ext.inspect} is not a module" elsif not (m = %w'Request Response NS_URI' - ext.constants).empty? raise ArgumentError, "#{ext.inspect} missing #{m*', '}" end consts = [ext::Request, ext::Response] if not consts.all?{|c| c.is_a? Class } raise TypeError, "#{ext.inspect}'s Request or Response is not a class" elsif not consts.all?{|c| ::OpenID::Extension > c } raise ArgumentError, "#{ext.inspect}'s Request or Response not a decendant of OpenID::Extension" end if not ext::NS_URI.is_a? String raise TypeError, "#{ext.inspect}'s NS_URI is not a string" elsif not uri = URI(ext::NS_URI) raise ArgumentError, "#{ext.inspect}'s NS_URI is not a valid uri" elsif not uri.scheme =~ /^https?$/ raise ArgumentError, "#{ext.inspect}'s NS_URI is not an http uri" elsif not uri.absolute? raise ArgumentError, "#{ext.inspect}'s NS_URI is not and absolute uri" end @extensions[ext] = args return ext::NS_URI end # A conveniance method that returns the namespace of all current # extensions used by this instance. def extension_namespaces @extensions.keys.map{|e|e::NS_URI} end end end end PKd9+&rack/auth/abstract/handler.rb&module Rack module Auth # Rack::Auth::AbstractHandler implements common authentication functionality. # # +realm+ should be set for all handlers. class AbstractHandler attr_accessor :realm def initialize(app, &authenticator) @app, @authenticator = app, authenticator end private def unauthorized(www_authenticate = challenge) return [ 401, { 'WWW-Authenticate' => www_authenticate.to_s }, [] ] end def bad_request [ 400, {}, [] ] end end end end PKd9brack/auth/abstract/request.rbumodule Rack module Auth class AbstractRequest def initialize(env) @env = env end def provided? !authorization_key.nil? end def parts @parts ||= @env[authorization_key].split(' ', 2) end def scheme @scheme ||= parts.first.downcase.to_sym end def params @params ||= parts.last end private AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION'] def authorization_key @authorization_key ||= AUTHORIZATION_KEYS.detect { |key| @env.has_key?(key) } end end end end PKd91r0 + rack/auth/digest/md5.rb+ require 'rack/auth/abstract/handler' require 'rack/auth/digest/request' require 'rack/auth/digest/params' require 'rack/auth/digest/nonce' require 'digest/md5' module Rack module Auth module Digest # Rack::Auth::Digest::MD5 implements the MD5 algorithm version of # HTTP Digest Authentication, as per RFC 2617. # # Initialize with the [Rack] application that you want protecting, # and a block that looks up a plaintext password for a given username. # # +opaque+ needs to be set to a constant base64/hexadecimal string. # class MD5 < AbstractHandler attr_accessor :opaque attr_writer :passwords_hashed def initialize(app) super @passwords_hashed = nil end def passwords_hashed? !!@passwords_hashed end def call(env) auth = Request.new(env) unless auth.provided? return unauthorized end if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth) return bad_request end if valid?(auth) if auth.nonce.stale? return unauthorized(challenge(:stale => true)) else env['REMOTE_USER'] = auth.username return @app.call(env) end end unauthorized end private QOP = 'auth'.freeze def params(hash = {}) Params.new do |params| params['realm'] = realm params['nonce'] = Nonce.new.to_s params['opaque'] = H(opaque) params['qop'] = QOP hash.each { |k, v| params[k] = v } end end def challenge(hash = {}) "Digest #{params(hash)}" end def valid?(auth) valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth) end def valid_qop?(auth) QOP == auth.qop end def valid_opaque?(auth) H(opaque) == auth.opaque end def valid_nonce?(auth) auth.nonce.valid? end def valid_digest?(auth) digest(auth, @authenticator.call(auth.username)) == auth.response end def md5(data) ::Digest::MD5.hexdigest(data) end alias :H :md5 def KD(secret, data) H([secret, data] * ':') end def A1(auth, password) [ auth.username, auth.realm, password ] * ':' end def A2(auth) [ auth.method, auth.uri ] * ':' end def digest(auth, password) password_hash = passwords_hashed? ? password : H(A1(auth, password)) KD(password_hash, [ auth.nonce, auth.nc, auth.cnonce, QOP, H(A2(auth)) ] * ':') end end end end end PKd9rack/auth/digest/nonce.rb8require 'digest/md5' module Rack module Auth module Digest # Rack::Auth::Digest::Nonce is the default nonce generator for the # Rack::Auth::Digest::MD5 authentication handler. # # +private_key+ needs to set to a constant string. # # +time_limit+ can be optionally set to an integer (number of seconds), # to limit the validity of the generated nonces. class Nonce class << self attr_accessor :private_key, :time_limit end def self.parse(string) new(*string.unpack("m*").first.split(' ', 2)) end def initialize(timestamp = Time.now, given_digest = nil) @timestamp, @given_digest = timestamp.to_i, given_digest end def to_s [([ @timestamp, digest ] * ' ')].pack("m*").strip end def digest ::Digest::MD5.hexdigest([ @timestamp, self.class.private_key ] * ':') end def valid? digest == @given_digest end def stale? !self.class.time_limit.nil? && (@timestamp - Time.now.to_i) < self.class.time_limit end def fresh? !stale? end end end end end PKd90rack/auth/digest/params.rbsmodule Rack module Auth module Digest class Params < Hash def self.parse(str) split_header_value(str).inject(new) do |header, param| k, v = param.split('=', 2) header[k] = dequote(v) header end end def self.dequote(str) # From WEBrick::HTTPUtils ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup ret.gsub!(/\\(.)/, "\\1") ret end def self.split_header_value(str) str.scan( /(\w+\=(?:"[^\"]+"|[^,]+))/n ).collect{ |v| v[0] } end def initialize super yield self if block_given? end def [](k) super k.to_s end def []=(k, v) super k.to_s, v.to_s end UNQUOTED = ['qop', 'nc', 'stale'] def to_s inject([]) do |parts, (k, v)| parts << "#{k}=" + (UNQUOTED.include?(k) ? v.to_s : quote(v)) parts end.join(', ') end def quote(str) # From WEBrick::HTTPUtils '"' << str.gsub(/[\\\"]/o, "\\\1") << '"' end end end end end PKd9 9rack/auth/digest/request.rb$require 'rack/auth/abstract/request' require 'rack/auth/digest/params' require 'rack/auth/digest/nonce' module Rack module Auth module Digest class Request < Auth::AbstractRequest def method @env['REQUEST_METHOD'] end def digest? :digest == scheme end def correct_uri? @env['PATH_INFO'] == uri end def nonce @nonce ||= Nonce.parse(params['nonce']) end def params @params ||= Params.parse(parts.last) end def method_missing(sym) if params.has_key? key = sym.to_s return params[key] end super end end end end end PKd9nrack/handler/cgi.rbjmodule Rack module Handler class CGI def self.run(app, options=nil) serve app end def self.serve(app) env = ENV.to_hash env.delete "HTTP_CONTENT_LENGTH" env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" env.update({"rack.version" => [0,1], "rack.input" => STDIN, "rack.errors" => STDERR, "rack.multithread" => false, "rack.multiprocess" => true, "rack.run_once" => true, "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" }) env["QUERY_STRING"] ||= "" env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] env["REQUEST_PATH"] ||= "/" status, headers, body = app.call(env) begin send_headers status, headers send_body body ensure body.close if body.respond_to? :close end end def self.send_headers(status, headers) STDOUT.print "Status: #{status}\r\n" headers.each { |k, vs| vs.each { |v| STDOUT.print "#{k}: #{v}\r\n" } } STDOUT.print "\r\n" STDOUT.flush end def self.send_body(body) body.each { |part| STDOUT.print part STDOUT.flush } end end end end PKd9i|wrack/handler/evented_mongrel.rbwrequire 'swiftcore/evented_mongrel' module Rack module Handler class EventedMongrel < Mongrel end end end PKd9i|rack/handler/fastcgi.rb|require 'fcgi' require 'socket' module Rack module Handler class FastCGI def self.run(app, options={}) file = options[:File] and STDIN.reopen(UNIXServer.new(file)) port = options[:Port] and STDIN.reopen(TCPServer.new(port)) FCGI.each { |request| serve request, app } end module ProperStream # :nodoc: def each # This is missing by default. while line = gets yield line end end def read(*args) if args.empty? super || "" # Empty string on EOF. else super end end end def self.serve(request, app) env = request.env env.delete "HTTP_CONTENT_LENGTH" request.in.extend ProperStream env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" env.update({"rack.version" => [0,1], "rack.input" => request.in, "rack.errors" => request.err, "rack.multithread" => false, "rack.multiprocess" => true, "rack.run_once" => false, "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" }) env["QUERY_STRING"] ||= "" env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] env["REQUEST_PATH"] ||= "/" env.delete "PATH_INFO" if env["PATH_INFO"] == "" status, headers, body = app.call(env) begin send_headers request.out, status, headers send_body request.out, body ensure body.close if body.respond_to? :close request.finish end end def self.send_headers(out, status, headers) out.print "Status: #{status}\r\n" headers.each { |k, vs| vs.each { |v| out.print "#{k}: #{v}\r\n" } } out.print "\r\n" out.flush end def self.send_body(out, body) body.each { |part| out.print part out.flush } end end end end PKd9@rack/handler/lsws.rb@require 'lsapi' #require 'cgi' module Rack module Handler class LSWS def self.run(app, options=nil) while LSAPI.accept != nil serve app end end def self.serve(app) env = ENV.to_hash env.delete "HTTP_CONTENT_LENGTH" env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" env.update({"rack.version" => [0,1], "rack.input" => STDIN, "rack.errors" => STDERR, "rack.multithread" => false, "rack.multiprocess" => true, "rack.run_once" => false, "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" }) env["QUERY_STRING"] ||= "" env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] env["REQUEST_PATH"] ||= "/" status, headers, body = app.call(env) begin send_headers status, headers send_body body ensure body.close if body.respond_to? :close end end def self.send_headers(status, headers) print "Status: #{status}\r\n" headers.each { |k, vs| vs.each { |v| print "#{k}: #{v}\r\n" } } print "\r\n" STDOUT.flush end def self.send_body(body) body.each { |part| print part STDOUT.flush } end end end end PKd9*xM rack/handler/mongrel.rb )require 'mongrel' require 'stringio' module Rack module Handler class Mongrel < ::Mongrel::HttpHandler def self.run(app, options={}) server = ::Mongrel::HttpServer.new(options[:Host] || '0.0.0.0', options[:Port] || 8080) # Acts like Rack::URLMap, utilizing Mongrel's own path finding methods. # Use is similar to #run, replacing the app argument with a hash of # { path=>app, ... } or an instance of Rack::URLMap. if options[:map] if app.is_a? Hash app.each do |path, appl| path = '/'+path unless path[0] == ?/ server.register(path, Rack::Handler::Mongrel.new(appl)) end elsif app.is_a? URLMap app.instance_variable_get(:@mapping).each do |(host, path, appl)| next if !host.nil? && !options[:Host].nil? && options[:Host] != host path = '/'+path unless path[0] == ?/ server.register(path, Rack::Handler::Mongrel.new(appl)) end else raise ArgumentError, "first argument should be a Hash or URLMap" end else server.register('/', Rack::Handler::Mongrel.new(app)) end yield server if block_given? server.run.join end def initialize(app) @app = app end def process(request, response) env = {}.replace(request.params) env.delete "HTTP_CONTENT_TYPE" env.delete "HTTP_CONTENT_LENGTH" env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" env.update({"rack.version" => [0,1], "rack.input" => request.body || StringIO.new(""), "rack.errors" => STDERR, "rack.multithread" => true, "rack.multiprocess" => false, # ??? "rack.run_once" => false, "rack.url_scheme" => "http", }) env["QUERY_STRING"] ||= "" env.delete "PATH_INFO" if env["PATH_INFO"] == "" status, headers, body = @app.call(env) begin response.status = status.to_i headers.each { |k, vs| vs.each { |v| response.header[k] = v } } body.each { |part| response.body << part } response.finished ensure body.close if body.respond_to? :close end end end end end PKd9Q$rack/handler/scgi.rbrequire 'scgi' require 'stringio' module Rack module Handler class SCGI < ::SCGI::Processor attr_accessor :app def self.run(app, options=nil) new(options.merge(:app=>app, :host=>options[:Host], :port=>options[:Port], :socket=>options[:Socket])).listen end def initialize(settings = {}) @app = settings[:app] @log = Object.new def @log.info(*args); end def @log.error(*args); end super(settings) end def process_request(request, input_body, socket) env = {}.replace(request) env.delete "HTTP_CONTENT_TYPE" env.delete "HTTP_CONTENT_LENGTH" env["REQUEST_PATH"], env["QUERY_STRING"] = env["REQUEST_URI"].split('?', 2) env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] env["PATH_INFO"] = env["REQUEST_PATH"] env["QUERY_STRING"] ||= "" env["SCRIPT_NAME"] = "" env.update({"rack.version" => [0,1], "rack.input" => StringIO.new(input_body), "rack.errors" => STDERR, "rack.multithread" => true, "rack.multiprocess" => true, "rack.run_once" => false, "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" }) status, headers, body = app.call(env) begin socket.write("Status: #{status}\r\n") headers.each do |k, vs| vs.each {|v| socket.write("#{k}: #{v}\r\n")} end socket.write("\r\n") body.each {|s| socket.write(s)} ensure body.close if body.respond_to? :close end end end end end PKd9G/*rack/handler/servlet.rb*#-- # Copyright 2007-2008 Sun Microsystems, Inc. # This source code is available under the MIT license. # See the file LICENSE.txt for details. #++ require 'jruby/rack' module Rack module Handler class Servlet def initialize(rack_app) @rack_app = rack_app end def call(servlet_env) JRuby::Rack::Response.new(@rack_app.call(create_env(servlet_env))) end def create_env(servlet_env) Env.new(servlet_env).to_hash end def create_lazy_env(servlet_env) LazyEnv.new(servlet_env).to_hash end end class Env BUILTINS = %w(rack.version rack.multithread rack.multiprocess rack.run_once rack.input rack.errors rack.url_scheme java.servlet_request java.servlet_context) REQUEST = %w(CONTENT_TYPE CONTENT_LENGTH REQUEST_METHOD SCRIPT_NAME REQUEST_URI PATH_INFO QUERY_STRING SERVER_NAME REMOTE_HOST REMOTE_ADDR REMOTE_USER SERVER_PORT) def initialize(servlet_env) @env = populate(LazyEnv.new(servlet_env).to_hash) end def populate(lazy_hash) hash = {} (BUILTINS + REQUEST).each {|k| lazy_hash[k]} # load builtins and request vars lazy_hash['HTTP_'] # load headers lazy_hash.keys.each {|k| hash[k] = lazy_hash[k]} hash end def to_hash @env end end class LazyEnv def initialize(servlet_env) @env = Hash.new {|h,k| load_env_key(h,k)} @servlet_env = servlet_env load_servlet_request_attributes end def to_hash @env end def load_env_key(env, key) if respond_to?("load__#{key}") send("load__#{key}", env) elsif key =~ /^(rack|java)/ load_builtin(env, key) elsif key =~ /^HTTP_/ load_headers(env, key) end end def load_servlet_request_attributes @servlet_env.getAttributeNames.each do |k| v = @servlet_env.getAttribute(k) case k when "SERVER_PORT", "CONTENT_LENGTH" @env[k] = v.to_s if v.to_i >= 0 when "CONTENT_TYPE" @env[k] = v if v else if v @env[k] = v else @env[k] = "" end end end end def load_headers(env, key) unless @headers_added @headers_added = true @servlet_env.getHeaderNames.each do |h| next if h =~ /^Content-(Type|Length)$/i k = "HTTP_#{h.upcase.gsub(/-/, '_')}" env[k] = @servlet_env.getHeader(h) unless env.has_key?(k) end end if env.has_key?(key) env[key] else nil end end def load_builtin(env, key) case key when 'rack.version' then env[key] = Rack::VERSION when 'rack.multithread' then env[key] = true when 'rack.multiprocess' then env[key] = false when 'rack.run_once' then env[key] = false when 'rack.input' then env[key] = @servlet_env.to_io when 'rack.errors' then env[key] = JRuby::Rack::ServletLog.new when 'rack.url_scheme' then env[key] = @servlet_env.getScheme when 'java.servlet_request' then env[key] = @servlet_env when 'java.servlet_context' then env[key] = $servlet_context else nil end end def load__CONTENT_TYPE(env) content_type = @servlet_env.getContentType env["CONTENT_TYPE"] = content_type if content_type end def load__CONTENT_LENGTH(env) content_length = @servlet_env.getContentLength env["CONTENT_LENGTH"] = content_length.to_s if content_length >= 0 end def load__REQUEST_METHOD(env) env["REQUEST_METHOD"] = @servlet_env.getMethod || "GET" end def load__SCRIPT_NAME(env) context_path = @servlet_env.getContextPath || "" env["SCRIPT_NAME"] = "#{context_path}#{@servlet_env.getServletPath}" end def load__REQUEST_URI(env) env["REQUEST_URI"] = @servlet_env.getRequestURI || "" env["REQUEST_URI"] += "?#{@servlet_env.getQueryString}" if @servlet_env.getQueryString env["REQUEST_URI"] end def load__PATH_INFO(env) path_info = @servlet_env.getServletPath || "" path_info += @servlet_env.getPathInfo if @servlet_env.getPathInfo env["PATH_INFO"] = path_info end def load__QUERY_STRING(env) env["QUERY_STRING"] = @servlet_env.getQueryString || "" end def load__SERVER_NAME(env) env["SERVER_NAME"] = @servlet_env.getServerName || "" end def load__REMOTE_HOST(env) env["REMOTE_HOST"] = @servlet_env.getRemoteHost || "" end def load__REMOTE_ADDR(env) env["REMOTE_ADDR"] = @servlet_env.getRemoteAddr || "" end def load__REMOTE_USER(env) env["REMOTE_USER"] = @servlet_env.getRemoteUser || "" end def load__SERVER_PORT(env) env["SERVER_PORT"] = @servlet_env.getServerPort.to_s end end end end PKd9orack/handler/webrick.rbrequire 'webrick' require 'stringio' module Rack module Handler class WEBrick < WEBrick::HTTPServlet::AbstractServlet def self.run(app, options={}) server = ::WEBrick::HTTPServer.new(options) server.mount "/", Rack::Handler::WEBrick, app trap(:INT) { server.shutdown } yield server if block_given? server.start end def initialize(server, app) super server @app = app end def service(req, res) env = req.meta_vars env.delete_if { |k, v| v.nil? } env.update({"rack.version" => [0,1], "rack.input" => StringIO.new(req.body.to_s), "rack.errors" => STDERR, "rack.multithread" => true, "rack.multiprocess" => false, "rack.run_once" => false, "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" }) env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] env["QUERY_STRING"] ||= "" env["REQUEST_PATH"] ||= "/" env.delete "PATH_INFO" if env["PATH_INFO"] == "" status, headers, body = @app.call(env) begin res.status = status.to_i headers.each { |k, vs| vs.each { |v| res[k] = v } } body.each { |part| res.body << part } ensure body.close if body.respond_to? :close end end end end end PKd9rack/session/abstract/PKd9޴]Xrack/session/cookie.rbXmodule Rack module Session # Rack::Session::Cookie provides simple cookie based session management. # The session is a Ruby Hash stored as base64 encoded marshalled data # set to :key (default: rack.session). # # Example: # # use Rack::Session::Cookie, :key => 'rack.session', # :domain => 'foo.com', # :path => '/', # :expire_after => 2592000 # # All parameters are optional. class Cookie def initialize(app, options={}) @app = app @key = options[:key] || "rack.session" @default_options = {:domain => nil, :path => "/", :expire_after => nil}.merge(options) end def call(env) load_session(env) status, headers, body = @app.call(env) commit_session(env, status, headers, body) end private def load_session(env) request = Rack::Request.new(env) session_data = request.cookies[@key] begin session_data = session_data.unpack("m*").first session_data = Marshal.load(session_data) env["rack.session"] = session_data rescue env["rack.session"] = Hash.new end env["rack.session.options"] = @default_options.dup end def commit_session(env, status, headers, body) session_data = Marshal.dump(env["rack.session"]) session_data = [session_data].pack("m*") if session_data.size > (4096 - @key.size) env["rack.errors"].puts("Warning! Rack::Session::Cookie data size exceeds 4K. Content dropped.") [status, headers, body] else options = env["rack.session.options"] cookie = Hash.new cookie[:value] = session_data cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil? response = Rack::Response.new(body, status, headers) response.set_cookie(@key, cookie.merge(options)) response.to_a end end end end end PKd9@: 5 rack/session/memcache.rb5 # AUTHOR: blink ; blink#ruby-lang@irc.freenode.net require 'rack/session/abstract/id' require 'memcache' module Rack module Session # Rack::Session::Memcache provides simple cookie based session management. # Session data is stored in memcached. The corresponding session key is # maintained in the cookie. # You may treat Session::Memcache as you would Session::Pool with the # following caveats. # # * Setting :expire_after to 0 would note to the Memcache server to hang # onto the session data until it would drop it according to it's own # specifications. However, the cookie sent to the client would expire # immediately. # # Note that memcache does drop data before it may be listed to expire. For # a full description of behaviour, please see memcache's documentation. class Memcache < Abstract::ID attr_reader :mutex, :pool DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge({ :namespace => 'rack:session', :memcache_server => 'localhost:11211' }) def initialize(app, options={}) super @pool = MemCache.new @default_options[:memcache_server], @default_options unless @pool.servers.any?{|s|s.alive?} raise "#{self} unable to find server during initialization." end @mutex = Mutex.new end private def get_session(env, sid) session = sid && @pool.get(sid) unless session and session.is_a?(Hash) session = {} lc = 0 @mutex.synchronize do begin raise RuntimeError, 'Unique id finding looping excessively' if (lc+=1) > 1000 sid = "%08x" % rand(0xffffffff) ret = @pool.add(sid, session) end until /^STORED/ =~ ret end end class << session @deleted = [] def delete key (@deleted||=[]) << key super end end [sid, session] rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted warn "#{self} is unable to find server." warn $!.inspect return [ nil, {} ] end def set_session(env, sid) session = env['rack.session'] options = env['rack.session.options'] expiry = options[:expire_after] || 0 o, s = @mutex.synchronize do old_session = @pool.get(sid) unless old_session.is_a?(Hash) warn 'Session not properly initialized.' if $DEBUG old_session = {} @pool.add sid, old_session, expiry end session.instance_eval do @deleted.each{|k| old_session.delete(k) } if defined? @deleted end @pool.set sid, old_session.merge(session), expiry [old_session, session] end s.each do |k,v| next unless o.has_key?(k) and v != o[k] warn "session value assignment collision at #{k.inspect}:"+ "\n\t#{o[k].inspect}\n\t#{v.inspect}" end if $DEBUG and env['rack.multithread'] return true rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted warn "#{self} is unable to find server." warn $!.inspect return false end end end end PKd9bi* % rack/session/pool.rb% # AUTHOR: blink ; blink#ruby-lang@irc.freenode.net # THANKS: # apeiros, for session id generation, expiry setup, and threadiness # sergio, threadiness and bugreps require 'rack/session/abstract/id' require 'thread' module Rack module Session # Rack::Session::Pool provides simple cookie based session management. # Session data is stored in a hash held by @pool. # In the context of a multithreaded environment, sessions being # committed to the pool is done in a merging manner. # # Example: # myapp = MyRackApp.new # sessioned = Rack::Session::Pool.new(myapp, # :key => 'rack.session', # :domain => 'foo.com', # :path => '/', # :expire_after => 2592000 # ) # Rack::Handler::WEBrick.run sessioned class Pool < Abstract::ID attr_reader :mutex, :pool DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.dup def initialize(app, options={}) super @pool = Hash.new @mutex = Mutex.new end private def get_session(env, sid) session = @mutex.synchronize do unless sess = @pool[sid] and ((expires = sess[:expire_at]).nil? or expires > Time.now) @pool.delete_if{|k,v| expiry = v[:expire_at] and expiry < Time.now } begin sid = "%08x" % rand(0xffffffff) end while @pool.has_key?(sid) end @pool[sid] ||= {} end [sid, session] end def set_session(env, sid) options = env['rack.session.options'] expiry = options[:expire_after] && options[:at]+options[:expire_after] @mutex.synchronize do old_session = @pool[sid] old_session[:expire_at] = expiry if expiry session = old_session.merge(env['rack.session']) @pool[sid] = session session.each do |k,v| next unless old_session.has_key?(k) and v != old_session[k] warn "session value assignment collision at #{k}: #{old_session[k]} <- #{v}" end if $DEBUG and env['rack.multithread'] end return true rescue warn "#{self} is unable to find server." warn "#{env['rack.session'].inspect} has been lost." warn $!.inspect return false end end end end PKd9^ rack/session/abstract/id.rb# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net # bugrep: Andreas Zehnder require 'rack/utils' require 'time' module Rack module Session module Abstract # ID sets up a basic framework for implementing an id based sessioning # service. Cookies sent to the client for maintaining sessions will only # contain an id reference. Only #get_session and #set_session should # need to be overwritten. # # All parameters are optional. # * :key determines the name of the cookie, by default it is # 'rack.session' # * :domain and :path set the related cookie values, by default # domain is nil, and the path is '/'. # * :expire_after is the number of seconds in which the session # cookie will expire. By default it is set not to provide any # expiry time. class ID attr_reader :key DEFAULT_OPTIONS = { :key => 'rack.session', :path => '/', :domain => nil, :expire_after => nil } def initialize(app, options={}) @default_options = self.class::DEFAULT_OPTIONS.merge(options) @key = @default_options[:key] @default_context = context app end def call(env) @default_context.call(env) end def context(app) Rack::Utils::Context.new self, app do |env| load_session env response = app.call(env) commit_session env, response response end end private # Extracts the session id from provided cookies and passes it and the # environment to #get_session. It then sets the resulting session into # 'rack.session', and places options and session metadata into # 'rack.session.options'. def load_session(env) sid = (env['HTTP_COOKIE']||'')[/#{@key}=([^,;]+)/,1] sid, session = get_session(env, sid) unless session.is_a?(Hash) puts 'Session: '+sid.inspect+"\n"+session.inspect if $DEBUG raise TypeError, 'Session not a Hash' end options = @default_options. merge({ :id => sid, :by => self, :at => Time.now }) env['rack.session'] = session env['rack.session.options'] = options return true end # Acquires the session from the environment and the session id from # the session options and passes them to #set_session. It then # proceeds to set a cookie up in the response with the session's id. def commit_session(env, response) unless response.is_a?(Array) puts 'Response: '+response.inspect if $DEBUG raise ArgumentError, 'Response is not an array.' end options = env['rack.session.options'] unless options.is_a?(Hash) puts 'Options: '+options.inspect if $DEBUG raise TypeError, 'Options not a Hash' end sid, time, z = options.values_at(:id, :at, :by) unless self == z warn "#{self} not managing this session." return end unless env['rack.session'].is_a?(Hash) warn 'Session: '+sid.inspect+"\n"+session.inspect if $DEBUG raise TypeError, 'Session not a Hash' end unless set_session(env, sid) warn "Session not saved." if $DEBUG warn "#{env['rack.session'].inspect} has been lost."if $DEBUG return false end cookie = Utils.escape(@key)+'='+Utils.escape(sid) cookie<< "; domain=#{options[:domain]}" if options[:domain] cookie<< "; path=#{options[:path]}" if options[:path] if options[:expire_after] expiry = time + options[:expire_after] cookie<< "; expires=#{expiry.httpdate}" end case a = (h = response[1])['Set-Cookie'] when Array then a << cookie when String then h['Set-Cookie'] = [a, cookie] when nil then h['Set-Cookie'] = cookie end return true end # Should return [session_id, session]. All thread safety and session # retrival proceedures should occur here. # If nil is provided as the session id, generation of a new valid id # should occur within. def get_session(env, sid) raise '#get_session needs to be implemented.' end # All thread safety and session storage proceedures should occur here. # Should return true or false dependant on whether or not the session # was saved or not. def set_session(env, sid) raise '#set_session needs to be implemented.' end end end end end PKd9 META-INF/PKd9 rMETA-INF/jruby-rack.tldT 1.0 jruby-rack urn:org.jruby.rack rails org.jruby.rack.RackTag empty Makes requests to the rails application and renders the results to the page path true true java.lang.String params false true java.lang.String rack org.jruby.rack.RackTag empty Makes requests to the rack application and renders the results to the page path true true java.lang.String params false true java.lang.String PKd9|META-INF/MANIFEST.MFjManifest-Version: 1.0 Created-By: Buildr Build-By: nicksieger Build-Jdk: 1.5.0_13 Implementation-Title: JRuby Rack adapter Implementation-Version: PK4d9 A_META-INF/PK4d9|eMETA-INF/MANIFEST.MFPK4d9 r_META-INF/jruby-rack.tldPK4d9A&cgi/PK4d9 Afcgi/session/PK4d95n !cgi/session/java_servlet_store.rbPK4d9AMjruby/PK4d9B750 jruby/rack.rbPK4d9 Ajruby/rack/PK4d9Agjruby/rack/boot/PK4d9˟o'=jruby/rack/boot/merb.rbPK4d9/Sr>jruby/rack/boot/rack.rbPK4d9p?jruby/rack/boot/rails.rbPK4d9 3 jruby/rack/merb.rbPK4d9,'lgsjruby/rack/rails.rbPK4d9jruby/rack/rails_boot.rbPK4d96(#-jruby/rack/rails_ext.rbPK4d9~ŭ#jruby/rack/servlet_ext.rbPK4d9.K'jruby/rack/servlet_helper.rbPK4d9Aorg/PK4d9 A'org/jruby/PK4d9ATorg/jruby/rack/PK4d9D2MH-org/jruby/rack/DefaultRackApplication$1.classPK4d9% l g +Rorg/jruby/rack/DefaultRackApplication.classPK4d94org/jruby/rack/DefaultRackApplicationFactory$1.classPK4d94)org/jruby/rack/DefaultRackApplicationFactory$2.classPK4d9;L#6Uorg/jruby/rack/DefaultRackApplicationFactory$3$1.classPK4d94M!org/jruby/rack/DefaultRackApplicationFactory$3.classPK4d94l'org/jruby/rack/DefaultRackApplicationFactory$4.classPK4d9~qlK.org/jruby/rack/DefaultRackApplicationFactory$ApplicationObjectFactory.classPK4d9X20org/jruby/rack/DefaultRackApplicationFactory.classPK4d96l *Horg/jruby/rack/DefaultRackDispatcher.classPK4d9X5#4@Torg/jruby/rack/PoolingRackApplicationFactory$1.classPK4d9m+2\org/jruby/rack/PoolingRackApplicationFactory.classPK4d9 SSje$xorg/jruby/rack/RackApplication.classPK4d9"+Gzorg/jruby/rack/RackApplicationFactory.classPK4d9V^#|org/jruby/rack/RackDispatcher.classPK4d9uGr!~org/jruby/rack/RackFilter$1.classPK4d9̏!org/jruby/rack/RackFilter$2.classPK4d9R`_Z57org/jruby/rack/RackFilter$ResponseStatusCapture.classPK4d9@l org/jruby/rack/RackFilter.classPK4d9~E0org/jruby/rack/RackInitializationException.classPK4d9u9w)$!͠org/jruby/rack/RackResponse.classPK4d919 5org/jruby/rack/RackServlet.classPK4d91+uID/ org/jruby/rack/RackServletContextListener.classPK4d9M4/org/jruby/rack/RackTag$1.classPK4d9ձ|c ^ org/jruby/rack/RackTag.classPK4d9<1org/jruby/rack/SharedRackApplicationFactory.classPK4d9A Torg/jruby/rack/merb/PK4d9S4id46org/jruby/rack/merb/MerbRackApplicationFactory.classPK4d9O4org/jruby/rack/merb/MerbServletContextListener.classPK4d9Aorg/jruby/rack/rails/PK4d9¼Dpk67org/jruby/rack/rails/RailsRackApplicationFactory.classPK4d9gJ@;6org/jruby/rack/rails/RailsServletContextListener.classPK4d9Aorg/jruby/webapp/PK4d9_3."org/jruby/webapp/FileServlet.classPK4d9d_+org/jruby/webapp/RailsContextListener.classPK4d961#org/jruby/webapp/RailsServlet.classPK4d9 rack.rbPK4d9Avrack/PK4d9 A@rack/adapter/PK4d9{J6orack/adapter/camping.rbPK4d9'uqrack/adapter/rails.rbPK4d9 AArack/auth/PK4d9Arack/auth/abstract/PK4d9+&rack/auth/abstract/handler.rbPK4d9b@rack/auth/abstract/request.rbPK4d9Wӄrack/auth/basic.rbPK4d9Arack/auth/digest/PK4d91r0 +  rack/auth/digest/md5.rbPK4d9orack/auth/digest/nonce.rbPK4d90rrack/auth/digest/params.rbPK4d9 9;rack/auth/digest/request.rbPK4d9[>CCrack/auth/openid.rbPK4d9;Arack/builder.rbPK4d9Frack/cascade.rbPK4d9wIrack/commonlogger.rbPK4d9`Orack/deflater.rbPK4d9HLAjeUrack/directory.rbPK4d9Q $_ cirack/file.rbPK4d92 SNwrack/handler.rbPK4d9 Anwrack/handler/PK4d9nTrack/handler/cgi.rbPK4d9i|wrack/handler/evented_mongrel.rbPK4d9i|rack/handler/fastcgi.rbPK4d9@rack/handler/lsws.rbPK4d9*xM rack/handler/mongrel.rbPK4d9Q$ rack/handler/scgi.rbPK4d9G/*rack/handler/servlet.rbPK4d9oN&rack/handler/webrick.rbPK4d95F;A; }rack/lint.rbPK4d9brack/lobster.rbPK4d9D d rack/mock.rbPK4d9yN<rack/recursive.rbPK4d9.lrack/reloader.rbPK4d9rrack/request.rbPK4d9@h?:rack/response.rbPK4d9 Arack/session/PK4d9A,rack/session/abstract/PK4d9^ 1Lrack/session/abstract/id.rbPK4d9޴]X,rack/session/cookie.rbPK4d9@: 5 e5rack/session/memcache.rbPK4d9bi* % Brack/session/pool.rbPK4d9+**Grack/showexceptions.rbPK4d9~ y .3rack/showstatus.rbPK4d9cb?rack/static.rbPK4d91Drack/urlmap.rbPK4d9> F&$!$ vKrack/utils.rbPKll]f