Rc@s"dZddkZddkZddkZddkZddkZddkZddklZl Z ddk l Z ddk l Z lZddklZeiiZeiiZeiiZeiiZeidZeiZeidZeid Zeid Zeid Zeid Z eid Z!eidZ"dZ#e$dZ%e&a'e%de$a(t(e_)e$a*dZ+e,dddddddddddddd d!d"d#d$fZ-e,ddddfZ.d%Z/d&Z0d'Z1e$d(Z2e$d)Z3d*e$e$e$d+Z4e$d,Z5d-Z6e$d.Z7e$e$e$d/Z8d0Z9d1Z:d2Z;d3Z<e$d4Z=d5d6e>e>e$e$e$fe>e$e$e$d7 Z?dd8d9Z@d:eAfd;YZBd<eAfd=YZCe>d>ZDd?ZEd@ZFdS(AsF This file is part of the web2py Web Framework Copyrighted by Massimo Di Pierro License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html) gluon.rewrite parses incoming URLs and formats outgoing URLs for gluon.html.URL. In addition, it rewrites both incoming and outgoing URLs based on the (optional) user-supplied routes.py, which also allows for rewriting of certain error messages. routes.py supports two styles of URL rewriting, depending on whether 'routers' is defined. Refer to router.example.py and routes.example.py for additional documentation. iN(tStoragetList(tHTTP(tabspatht read_file(tglobal_settingssweb2py.rewrites(?(.*)s@^(?Phttp|https|HTTP|HTTPS)\://(?P[^/]*)(?P.*)s^(_[\d]+\.[\d]+\.[\d]+)$sN^/((?P\w+)(/(?P\w+)(/(?P(?P\w+)(\.(?P[\w.]+))?(?P.*)))?)?)?$s [^\w/.@=-]c!Csvtddddddddd d d td dd ddddgdddddtdtdddddd}|S(s&return new copy of default base routertdefault_applicationtinitt applicationstALLtdefault_controllertdefaultt controllerstDEFAULTtdefault_functiontindext functionstdefault_languaget languagest root_statics favicon.icos robots.txtt map_statictdomainstexclusive_domaint map_hyphent acfe_matchs\w+$t file_matchs"([-+=@$%\w]|(?<=[-+=@$%\w])[./])*$t args_matchs([\w@ -]|(?<=[\w@ -])[.=])*$N(RtdicttNonetFalse(trouter((s%/opt/web-apps/web2py/gluon/rewrite.pyt_router_default;s$   cCst}|pd|_|pd|_d|_d|_g|_g|_g|_g|_g|_ d |_ d|_ dddd |_ d |_d |_|S( s%return new copy of default parameterstBASERR Rs%

%s

s

Internal error

Ticket issued:
%(ticket)stoffN(RtnameRR Rt routes_appt routes_int routes_outtroutes_onerrortroutes_apps_rawRt error_handlert error_messageterror_message_tickettrouterstlogging(tapptp((s%/opt/web-apps/web2py/gluon/rewrite.pyt_params_defaultWs             R.cCstidjoti|ntidjp ti ontidjo |GHntidjoti|nqtidjoti|nPtidjoti|n/tidjoti|nti|dS( s/Log rewrite activity under control of routes.pytdebugR"tprinttinfotwarningterrortcriticalN(tparamsR-tloggerR1R3R4R5R6(tstring((s%/opt/web-apps/web2py/gluon/rewrite.pyt log_rewriteqs RRR R RRRRtdomainRRt path_prefixRRRRRRcCs|i}|d}|d}| oT|oM|id}|d}|dherei/tLocationt__ROUTES_ONERROR__t/R=RAtWEB2PY_STATUS_CODEN(tinttstrtstatusRFt THREAD_LOCALtroutesR'tsetR\turllibt quote_plusRYRKRet startswithRRERRXtlstripR( t http_responseRQRHtticketRptkeystkeyturiRJRMRetmessage((s%/opt/web-apps/web2py/gluon/rewrite.pyttry_rewrite_on_errors>              cCs,tt|iid}|djotiiotd|i|fd|id|df}xtiiD]\}}||jo|djoPnhd|jo/d |||t i |i i |i f}n,d |||t i |i i |i f}td d |d |SqvWn|S(s6called from main.wsgibase to rewrite the http responseiis%s/%ss%s/*s*/%ss*/*RhR?s4%s&code=%s&ticket=%s&requested_uri=%s&request_url=%ss4%s?code=%s&ticket=%s&requested_uri=%s&request_url=%si/s.You are being redirected hereRj(RnRoRpRFRqRrR'RsR\RtRuRYRKReR(t http_objectRQRyRpRzR{tredirRe((s%/opt/web-apps/web2py/gluon/rewrite.pyttry_redirect_on_errors,          s routes.pycBsK|djo+eaeddate_dane|eoed|}d}n|dj o d}nZ|djoe |}ne d||}e |pdSe |i dd}ed|}y|d|UWn6e j o*}eid |ei|nXe|}xKdD]C}||jo0x-||D]} ||ie| qZWq<q<Wx-dD]%}||jo||||.*)s (?P<%s>\w+)s\g<%s>( tfindRtregex_anythingtfindallRtregex_attretcompiletDOTALL(tktvRYtk0tititem((s%/opt/web-apps/web2py/gluon/rewrite.pyRs,   c CsxKtD]C}||jo|i|tti}|djoDtt|it}|o tdt||fqn|i t||t||i| |i| |} td ||| | f| SqWtd|||f|S(s-filter incoming URI against a list of regexesR=RBRCt localhostRUis%s:%s://%s:%s %st REMOTE_ADDRswsgi.url_schemeRTtREQUEST_METHODREs%s: [%s] [%s] -> %ss%s: [%s] -> %s (not rewritten)(RER[RtmatchRtsubR:( RtregexesttagR RRbRR{tregextvaluet custom_envt rewritten((s%/opt/web-apps/web2py/gluon/rewrite.pyt regex_uris$ $   cCs|oti|tt_ng|oVtioLtot||dtqt |tid}ti|tt_n tt_t dtii |S(sF select a set of regex rewrite params for the current request R.R$sselect routing parameters: %s( RRER7RqRrR$R,RORXRR:R#(RYR.RQ((s%/opt/web-apps/web2py/gluon/rewrite.pyt regex_select,s cCs=ti}|idd }|d|o d|pd|d<|iot||id|d}ti|}|o.tt |i dd|i d n|i dd}|d |dN( RqRrRERR%Rtregex_redirectRRRntgroupRFRG(RRrtqueryRtrmatchRL((s%/opt/web-apps/web2py/gluon/rewrite.pytregex_filter_in>s$ $  . $cCs|iiddS(NRt_(R[R(R{((s%/opt/web-apps/web2py/gluon/rewrite.pytsluggifyUscCs td|iddddS(Nisinvalid requestt web2py_errors invalid path(RR*(Rr((s%/opt/web-apps/web2py/gluon/rewrite.pyt invalid_urlXs c Cstd|d|ti}|iot|}n|iid|iDti |ii pd}|i dd}|i do!t |djo|d }nti|}|pt|n|idpd |_|iido|id|_n|id d jo|id }d|id i dd}}|ptdn|idd}ti|do|\}}nt|iid|d } tiit| |} | i| pt|n| ||fS|id p|i|_|id p|i|_ |idp|i!|_"|id|_#|i#pd|_$|i|i%jo d|_&nK|io1t'i(d|i} t)| id|_&nt)g|_&dd|fS(srewrite and parse incoming URLRYRQcss7x0|])\}}|iidd|fVqWdS(RRN(R[R(t.0RR((s%/opt/web-apps/web2py/gluon/rewrite.pys ks Rls\iitsR@tcRRtzt RiiRtfRthtmlN(*RRqRrR%RRYRRRttunquoteRJRRRGt regex_urlRRRtraw_argsRvRRRFt regex_versiontpjointapplications_parentRRRRR\R R]RR^t raw_extensiont extensionR(R_t regex_argsRR( RQRHRrRRR\tversiontfilenameRLt static_foldert static_fileR_((s%/opt/web-apps/web2py/gluon/rewrite.pyRP]sT    #"   c Csttdp tnti}to|S|io:|idd}|o|iddi}|i d}|djo|| }nd|id d |id d i||id di|df|d %ssroutes_out: [%s] not rewritten(thasattrRqRRrR,R&RFRER[RRtjoinRR:( ReRRrRLRbRRRttmpR((s%/opt/web-apps/web2py/gluon/rewrite.pyRWs2    + * REs0.0.0.0c  Csti|} | idi} | idi} | id}|id}|djot|}nt|to|d f}n|| ||d}}t i |}h |d6|d6| d 6| d 6|d 6|d 6|d 6|d6|d6| d6| d6}t }t i |dR=RARRRSRZRR.RliR@isat least /a/c/f is requireds%s/%ss /%s/%s/%sRs.%ss %ss ?%ss (%s)N(#tregex_full_urlRRR[RRGRRoRRtRRRRRYt uri_languageR,RORXRtdomain_applicationtdomain_controllerRwRFRtAssertionErrorRWRVRRRR\R]R^RR_(RetmethodtremotetoutR.tlangR;RYRaRbRcRt urlschemeturlhostR|RRJRMRRQRLRRRRdRRtresult((s%/opt/web-apps/web2py/gluon/rewrite.pyt filter_urls      $   ttktcCsti}|djo|iotd||fd|d|df}x|iD]q\}}||joX|djoPnBd|jo|dd ||f}n|dd ||f}|SqTWn|S( s,doctest/unittest interface to routes_onerroris%s/%ss%s/*s*/%ss*/*RhR?Riscode=%s&ticket=%s(RqRrR'Rs(RpR\RyRrRzR{RRe((s%/opt/web-apps/web2py/gluon/rewrite.pyt filter_errs        tMapUrlIncBseZdZdddZdZdZdZdZdZ dZ dZ d Z d Z d Zed Zed ZdZRS(slogic for mapping incoming URLscCss||_||_d|_d|_d|_d|_d|_d|_t |_ t |_ t |_ d|_t|_t|_|id}|iidd|_|id}d||id<|id|iod|ipd|id<|ido|d }nt|o|idpg|_|iid d |_|iid d i|_|iid di|_|iidd|_|_|ip/|iid|iid|_|_n|ipd\|_|_nd|ijo%|iidd\|_|_n|ip$|idjodnd|_ndS(sinitialize a map-in objectRR=RARlR?R@RiRRswsgi.url_schemeRTRRERBRCRDt80RUithttpst443N(s localhostR( RQRYRRR\tlanguageR]R^RRsR RRRRRRRRERRwRRRFR_RR[RaRRbRctrsplit(tselfRQRYR((s%/opt/web-apps/web2py/gluon/rewrite.pyt__init__/sF                && / % cCstii}|out|}|t|ijodSx1t|D]#}|||i|jodSqGWt|i||_ndS(s-strip path prefix, if present in its entiretyN(R,R R<RGR_txrangeR(Rtprefixt prefixlenR((s%/opt/web-apps/web2py/gluon/rewrite.pyt map_prefix_s    cCsti}d |_d |_d |_|i}|i o'|io||ijo ||_ nt|i o|o|i o ||_ nJ|i |i f|i jo_|i |i |i f\|_ |_|_|i |i d<|i|i d<|i|i d   $     cCs|i}|ii|it}t|iito|iii|id }n |ii}|i p|}| p|o>||jo1|pd|_ |i |o |i |jnW|i d}t|djo|d|_ |d|_n ||_ |i ttd|i |if|iii|i p#tdtiidd d n|io=|iii|i o#tdtiidd d nd S( shandle function.extensionR@Riiisroute: function.ext=%s.%sisinvalid requestRsinvalid functionsinvalid extensionN(RRRER]RsRRRRRR R^RRFRGRRXR:RRRRqRrR*(RRRRtfunc_ext((s%/opt/web-apps/web2py/gluon/rewrite.pyt map_functions4   !    $cCsUxN|iD]C}|iii|p'tdtiiddd|q q WdS(s7 check args against validation pattern isinvalid requestRsinvalid arg <%s>N(R_RRRRRqRrR*(Rtarg((s%/opt/web-apps/web2py/gluon/rewrite.pyt validate_args$s  cCs*|iiid|iiDdS(R@css7x0|])\}}|iidd|fVqWdS(RRN(R[R(RRR((s%/opt/web-apps/web2py/gluon/rewrite.pys 1s N(RQRYRR(R((s%/opt/web-apps/web2py/gluon/rewrite.pyR.s cCs|i|i_|i|i_|i|i_|i|i_|i|i_|io|i|i_nd|i|if}|i}|io(|i dd}|i dd}n|io%|idjo|d|i7}n|iod|i|f}nd|||io*t i ddi d |iDnd |i od |i nd f}||id <|id S(s update request from self build env.request_uri make lower-case versions of http headers in env s/%s/%sRt-RRs/%s%ss /%s%s%s%sRlcssx|]}t|VqWdS(N(Ro(RR!((s%/opt/web-apps/web2py/gluon/rewrite.pys Ms R@R?R>N(R\RQR]R^RR_RRRRRttquoteRRRYR(RR|R.((s%/opt/web-apps/web2py/gluon/rewrite.pytupdate_request3s.    7" cCs |idS(sreturn first argi(R_(R((s%/opt/web-apps/web2py/gluon/rewrite.pyRRscCsA|io*|ido|ididdS|idS(s-return first arg with optional hyphen mappingiRR(RR_R(R((s%/opt/web-apps/web2py/gluon/rewrite.pyRWscCs|o|iidndS(s7conditionally remove first arg and return new first argiN(R_R(Rtdopop((s%/opt/web-apps/web2py/gluon/rewrite.pyR^sN(t__name__t __module__t__doc__RRR RRRRRRRRRtpropertyRRR(((s%/opt/web-apps/web2py/gluon/rewrite.pyR,s0 >   - !  t MapUrlOutcBs;eZdZdZdZdZdZdZRS(slogic for mapping outgoing URLsc Csxtii|_|tjot||_n ti|_||_||_||_||_|djp |id|_ ||_ ||_ ||_ ||_ | |_| |_tii|_|ii|_|iii|it|_|ii|_|ii|_|ii|_|ii|_|ii|_tii|_|o |iii|_|o |iii|_t|iito"|iii|id|_n|ii|_|iio8|io.|i|ijo|i ot!dn|o|i"} | o'|io| |ijo | |_#n d|_#t$|_%t$|_&t$|_'t$|_(dS(sinitialize a map-out objectRsstatic/s(cross-domain conflict: must specify hostN()R,R RRRQRYR\R]Rvt is_staticR^R_R`RaRbRcRR RRERsRRRRRR<RRRRRRRRRRtomit_applicationt omit_languagetomit_controllert omit_function( RRQRYR\R]R^R_R`RaRbRcR((s%/opt/web-apps/web2py/gluon/rewrite.pyRgsP            ! 5!     cCs/|i p|i|ijo t|_ndS(somit language if possibleN(RRRXR((R((s%/opt/web-apps/web2py/gluon/rewrite.pyt omit_langscCs|i}|i o`|i|ijoMt|_|i|ijo-t|_|i |i jo t|_ qpqtn|i p|i }|i |jo t|_ n|i |i jo |i p|ipd}|i|jo t|_n|io3|i|ijo |i|ijo t|_n|io|i g}n |i}|io\| p|i|jo t|_ n|i o)| p|i|jo t|_qqn|i p|i|ijo t|_n|ioS|id|ijp+|id|ijp|id|jo t|_q<n|io4|i|ijp|i|jo t|_qzn|i o!|i|jo t|_ qn|ioD|ip$t|_ |io t|_qnt|_t|_ndS(somit what we can of a/c/fR@iN(RR_R^RRXR*R]R R)R\RR'RRRRRR(RR R&RR(RRRR R((s%/opt/web-apps/web2py/gluon/rewrite.pytomit_acfsT    - 0        B #      cCsd}|iot|iidd|_|iidd|_|idjo0|iid o|iidd|_qn|ip|d|i7}n|io;|it jo+|i o |d|id|i 7}n?|i p|d|i 7}n|i p|d|i7}n|i p|d|i7}n|ioddi|i|}n|io|S|pdS(sbuild acf from componentsR@RRRsstatic/Rl(RR\RR]RvR^R'R&RRR(RR)R*R<RR_(RRd((s%/opt/web-apps/web2py/gluon/rewrite.pyt build_acfs* $  %      cCs*tpdS|i|i|iS(s3convert components to /app/lang/controller/functionN(R,RR+R,R-(R((s%/opt/web-apps/web2py/gluon/rewrite.pyRds   (R!R"R#RR+R,R-Rd(((s%/opt/web-apps/web2py/gluon/rewrite.pyR%ds  5  E cCsstt_td|d|}|i|i|itioti |tt_n|o|i S|i \}}|o|i |||i fS|ioQ|itjoA|idjo1|id|ijo|i|in|i|i|i\}}|o|i |||i fS|i|i|i dd|i fS(sroute incoming URLRQRYRiN(R7RqRrRRR RR$RRER\RRRYRRRRR_RRRRR(RQRYR.tmapRRR((s%/opt/web-apps/web2py/gluon/rewrite.pyRO s4      C       c Cs1t|||||||||| } | iS(s supply /a/c/f (or /a/lang/c/f) portion of outgoing url The basic rule is that we can only make transformations that map_url_in can reverse. Suppose that the incoming arguments are a,c,f,args,lang and that the router defaults are da, dc, df, dl. We can perform these transformations trivially if args=[] and lang=None or dl: /da/dc/df => / /a/dc/df => /a /a/c/df => /a/c We would also like to be able to strip the default application or application/controller from URLs with function/args present, thus: /da/c/f/args => /c/f/args /da/dc/f/args => /f/args We use [applications] and [controllers] and {functions} to suppress ambiguous omissions. We assume that language names do not collide with a/c/f names. (R%Rd( RQRYR\R]R^R_R`RaRbRcR.((s%/opt/web-apps/web2py/gluon/rewrite.pyRV5scCs(t p |tjodStt|S(sKreturn a private copy of the effective router for the specified applicationN(R,RR(R((s%/opt/web-apps/web2py/gluon/rewrite.pytget_effective_routerUs(GR#RRR-Rt threadingRtt gluon.storageRRt gluon.httpRtgluon.fileutilsRRtgluon.settingsRRRRRRRt getLoggerR8tlocalRqRRRRRRRRRRR0RRR7RrR,R:RsRRRNRRRgR~RRRRRRRRRRPRWRRRtobjectRR%RORVR/(((s%/opt/web-apps/web2py/gluon/rewrite.pyts                        * m % j     @  X9 *