1*b4dd7d09SAndy Fiddaman#!/usr/bin/ksh93 2*b4dd7d09SAndy Fiddaman 3*b4dd7d09SAndy Fiddaman# 4*b4dd7d09SAndy Fiddaman# CDDL HEADER START 5*b4dd7d09SAndy Fiddaman# 6*b4dd7d09SAndy Fiddaman# The contents of this file are subject to the terms of the 7*b4dd7d09SAndy Fiddaman# Common Development and Distribution License (the "License"). 8*b4dd7d09SAndy Fiddaman# You may not use this file except in compliance with the License. 9*b4dd7d09SAndy Fiddaman# 10*b4dd7d09SAndy Fiddaman# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 11*b4dd7d09SAndy Fiddaman# or http://www.opensolaris.org/os/licensing. 12*b4dd7d09SAndy Fiddaman# See the License for the specific language governing permissions 13*b4dd7d09SAndy Fiddaman# and limitations under the License. 14*b4dd7d09SAndy Fiddaman# 15*b4dd7d09SAndy Fiddaman# When distributing Covered Code, include this CDDL HEADER in each 16*b4dd7d09SAndy Fiddaman# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 17*b4dd7d09SAndy Fiddaman# If applicable, add the following below this CDDL HEADER, with the 18*b4dd7d09SAndy Fiddaman# fields enclosed by brackets "[]" replaced with your own identifying 19*b4dd7d09SAndy Fiddaman# information: Portions Copyright [yyyy] [name of copyright owner] 20*b4dd7d09SAndy Fiddaman# 21*b4dd7d09SAndy Fiddaman# CDDL HEADER END 22*b4dd7d09SAndy Fiddaman# 23*b4dd7d09SAndy Fiddaman 24*b4dd7d09SAndy Fiddaman# 25*b4dd7d09SAndy Fiddaman# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 26*b4dd7d09SAndy Fiddaman# 27*b4dd7d09SAndy Fiddaman 28*b4dd7d09SAndy Fiddaman# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant 29*b4dd7d09SAndy Fiddamanexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin 30*b4dd7d09SAndy Fiddaman 31*b4dd7d09SAndy Fiddaman# Make sure all math stuff runs in the "C" locale to avoid problems 32*b4dd7d09SAndy Fiddaman# with alternative # radix point representations (e.g. ',' instead of 33*b4dd7d09SAndy Fiddaman# '.' in de_DE.*-locales). This needs to be set _before_ any 34*b4dd7d09SAndy Fiddaman# floating-point constants are defined in this script). 35*b4dd7d09SAndy Fiddamanif [[ "${LC_ALL}" != "" ]] ; then 36*b4dd7d09SAndy Fiddaman export \ 37*b4dd7d09SAndy Fiddaman LC_MONETARY="${LC_ALL}" \ 38*b4dd7d09SAndy Fiddaman LC_MESSAGES="${LC_ALL}" \ 39*b4dd7d09SAndy Fiddaman LC_COLLATE="${LC_ALL}" \ 40*b4dd7d09SAndy Fiddaman LC_CTYPE="${LC_ALL}" 41*b4dd7d09SAndy Fiddaman unset LC_ALL 42*b4dd7d09SAndy Fiddamanfi 43*b4dd7d09SAndy Fiddamanexport LC_NUMERIC=C 44*b4dd7d09SAndy Fiddaman 45*b4dd7d09SAndy Fiddamanfunction fatal_error 46*b4dd7d09SAndy Fiddaman{ 47*b4dd7d09SAndy Fiddaman print -u2 "${progname}: $*" 48*b4dd7d09SAndy Fiddaman exit 1 49*b4dd7d09SAndy Fiddaman} 50*b4dd7d09SAndy Fiddaman 51*b4dd7d09SAndy Fiddaman# parse HTTP return code, cookies etc. 52*b4dd7d09SAndy Fiddamanfunction parse_http_response 53*b4dd7d09SAndy Fiddaman{ 54*b4dd7d09SAndy Fiddaman nameref response="$1" 55*b4dd7d09SAndy Fiddaman typeset h statuscode statusmsg i 56*b4dd7d09SAndy Fiddaman 57*b4dd7d09SAndy Fiddaman # we use '\r' as additional IFS to filter the final '\r' 58*b4dd7d09SAndy Fiddaman IFS=$' \t\r' read -r h statuscode statusmsg # read HTTP/1.[01] <code> 59*b4dd7d09SAndy Fiddaman [[ "$h" != ~(Eil)HTTP/.* ]] && { print -u2 -f $"%s: HTTP/ header missing\n" "$0" ; return 1 ; } 60*b4dd7d09SAndy Fiddaman [[ "$statuscode" != ~(Elr)[0-9]* ]] && { print -u2 -f $"%s: invalid status code\n" "$0" ; return 1 ; } 61*b4dd7d09SAndy Fiddaman response.statuscode="$statuscode" 62*b4dd7d09SAndy Fiddaman response.statusmsg="$statusmsg" 63*b4dd7d09SAndy Fiddaman 64*b4dd7d09SAndy Fiddaman # skip remaining headers 65*b4dd7d09SAndy Fiddaman while IFS='' read -r i ; do 66*b4dd7d09SAndy Fiddaman [[ "$i" == $'\r' ]] && break 67*b4dd7d09SAndy Fiddaman 68*b4dd7d09SAndy Fiddaman # strip '\r' at the end 69*b4dd7d09SAndy Fiddaman i="${i/~(Er)$'\r'/}" 70*b4dd7d09SAndy Fiddaman 71*b4dd7d09SAndy Fiddaman case "$i" in 72*b4dd7d09SAndy Fiddaman ~(Eli)Content-Type:.*) 73*b4dd7d09SAndy Fiddaman response.content_type="${i/~(El).*:[[:blank:]]*/}" 74*b4dd7d09SAndy Fiddaman ;; 75*b4dd7d09SAndy Fiddaman ~(Eli)Content-Length:[[:blank:]]*[0-9]*) 76*b4dd7d09SAndy Fiddaman integer response.content_length="${i/~(El).*:[[:blank:]]*/}" 77*b4dd7d09SAndy Fiddaman ;; 78*b4dd7d09SAndy Fiddaman ~(Eli)Transfer-Encoding:.*) 79*b4dd7d09SAndy Fiddaman response.transfer_encoding="${i/~(El).*:[[:blank:]]*/}" 80*b4dd7d09SAndy Fiddaman ;; 81*b4dd7d09SAndy Fiddaman esac 82*b4dd7d09SAndy Fiddaman done 83*b4dd7d09SAndy Fiddaman 84*b4dd7d09SAndy Fiddaman return 0 85*b4dd7d09SAndy Fiddaman} 86*b4dd7d09SAndy Fiddaman 87*b4dd7d09SAndy Fiddamanfunction cat_http_body 88*b4dd7d09SAndy Fiddaman{ 89*b4dd7d09SAndy Fiddaman typeset emode="$1" 90*b4dd7d09SAndy Fiddaman typeset hexchunksize="0" 91*b4dd7d09SAndy Fiddaman integer chunksize=0 92*b4dd7d09SAndy Fiddaman 93*b4dd7d09SAndy Fiddaman if [[ "${emode}" == "chunked" ]] ; then 94*b4dd7d09SAndy Fiddaman while IFS=$'\r' read hexchunksize && 95*b4dd7d09SAndy Fiddaman [[ "${hexchunksize}" == ~(Elri)[0-9abcdef]+ ]] && 96*b4dd7d09SAndy Fiddaman (( chunksize=$( printf "16#%s\n" "${hexchunksize}" ) )) && (( chunksize > 0 )) ; do 97*b4dd7d09SAndy Fiddaman dd bs=1 count="${chunksize}" 2>/dev/null 98*b4dd7d09SAndy Fiddaman done 99*b4dd7d09SAndy Fiddaman else 100*b4dd7d09SAndy Fiddaman cat 101*b4dd7d09SAndy Fiddaman fi 102*b4dd7d09SAndy Fiddaman 103*b4dd7d09SAndy Fiddaman return 0 104*b4dd7d09SAndy Fiddaman} 105*b4dd7d09SAndy Fiddaman 106*b4dd7d09SAndy Fiddamanfunction request_tinyurl 107*b4dd7d09SAndy Fiddaman{ 108*b4dd7d09SAndy Fiddaman # site setup 109*b4dd7d09SAndy Fiddaman typeset url_host="tinyurl.com" 110*b4dd7d09SAndy Fiddaman typeset url_path="/api-create.php" 111*b4dd7d09SAndy Fiddaman typeset url="http://${url_host}${url_path}" 112*b4dd7d09SAndy Fiddaman integer netfd # http stream number 113*b4dd7d09SAndy Fiddaman typeset inputurl="$1" 114*b4dd7d09SAndy Fiddaman compound httpresponse # http response 115*b4dd7d09SAndy Fiddaman typeset request="" 116*b4dd7d09SAndy Fiddaman 117*b4dd7d09SAndy Fiddaman # we assume "inputurl" is a correctly encoded URL which doesn't 118*b4dd7d09SAndy Fiddaman # require any further mangling 119*b4dd7d09SAndy Fiddaman url_path+="?url=${inputurl}" 120*b4dd7d09SAndy Fiddaman 121*b4dd7d09SAndy Fiddaman request="GET ${url_path} HTTP/1.1\r\n" 122*b4dd7d09SAndy Fiddaman request+="Host: ${url_host}\r\n" 123*b4dd7d09SAndy Fiddaman request+="User-Agent: ${http_user_agent}\r\n" 124*b4dd7d09SAndy Fiddaman request+="Connection: close\r\n" 125*b4dd7d09SAndy Fiddaman 126*b4dd7d09SAndy Fiddaman redirect {netfd}<> "/dev/tcp/${url_host}/80" 127*b4dd7d09SAndy Fiddaman (( $? != 0 )) && { print -u2 -f $"%s: Could not open connection to %s.\n" "$0" "${url_host}" ; return 1 ; } 128*b4dd7d09SAndy Fiddaman 129*b4dd7d09SAndy Fiddaman # send http post 130*b4dd7d09SAndy Fiddaman { 131*b4dd7d09SAndy Fiddaman print -n -- "${request}\r\n" 132*b4dd7d09SAndy Fiddaman } >&${netfd} 133*b4dd7d09SAndy Fiddaman 134*b4dd7d09SAndy Fiddaman # process reply 135*b4dd7d09SAndy Fiddaman parse_http_response httpresponse <&${netfd} 136*b4dd7d09SAndy Fiddaman response="${ cat_http_body "${httpresponse.transfer_encoding}" <&${netfd} ; }" 137*b4dd7d09SAndy Fiddaman 138*b4dd7d09SAndy Fiddaman # close connection 139*b4dd7d09SAndy Fiddaman redirect {netfd}<&- 140*b4dd7d09SAndy Fiddaman 141*b4dd7d09SAndy Fiddaman if (( httpresponse.statuscode >= 200 && httpresponse.statuscode <= 299 )) ; then 142*b4dd7d09SAndy Fiddaman print -r -- "${response}" 143*b4dd7d09SAndy Fiddaman return 0 144*b4dd7d09SAndy Fiddaman else 145*b4dd7d09SAndy Fiddaman print -u2 -f $"tinyurl response was (%s,%s):\n%s\n" "${httpresponse.statuscode}" "${httpresponse.statusmsg}" "${response}" 146*b4dd7d09SAndy Fiddaman return 1 147*b4dd7d09SAndy Fiddaman fi 148*b4dd7d09SAndy Fiddaman 149*b4dd7d09SAndy Fiddaman # not reached 150*b4dd7d09SAndy Fiddaman} 151*b4dd7d09SAndy Fiddaman 152*b4dd7d09SAndy Fiddamanfunction request_trimurl 153*b4dd7d09SAndy Fiddaman{ 154*b4dd7d09SAndy Fiddaman # site setup 155*b4dd7d09SAndy Fiddaman typeset url_host="api.tr.im" 156*b4dd7d09SAndy Fiddaman typeset url_path="/api/trim_url.xml" 157*b4dd7d09SAndy Fiddaman typeset url="http://${url_host}${url_path}" 158*b4dd7d09SAndy Fiddaman integer netfd # http stream number 159*b4dd7d09SAndy Fiddaman typeset inputurl="$1" 160*b4dd7d09SAndy Fiddaman compound httpresponse # http response 161*b4dd7d09SAndy Fiddaman typeset request="" 162*b4dd7d09SAndy Fiddaman 163*b4dd7d09SAndy Fiddaman # we assume "inputurl" is a correctly encoded URL which doesn't 164*b4dd7d09SAndy Fiddaman # require any further mangling 165*b4dd7d09SAndy Fiddaman url_path+="?url=${inputurl}" 166*b4dd7d09SAndy Fiddaman 167*b4dd7d09SAndy Fiddaman request="GET ${url_path} HTTP/1.1\r\n" 168*b4dd7d09SAndy Fiddaman request+="Host: ${url_host}\r\n" 169*b4dd7d09SAndy Fiddaman request+="User-Agent: ${http_user_agent}\r\n" 170*b4dd7d09SAndy Fiddaman request+="Connection: close\r\n" 171*b4dd7d09SAndy Fiddaman 172*b4dd7d09SAndy Fiddaman redirect {netfd}<> "/dev/tcp/${url_host}/80" 173*b4dd7d09SAndy Fiddaman (( $? != 0 )) && { print -u2 -f $"%s: Could not open connection to %s.\n" "$0" "${url_host}" ; return 1 ; } 174*b4dd7d09SAndy Fiddaman 175*b4dd7d09SAndy Fiddaman # send http post 176*b4dd7d09SAndy Fiddaman { 177*b4dd7d09SAndy Fiddaman print -n -- "${request}\r\n" 178*b4dd7d09SAndy Fiddaman } >&${netfd} 179*b4dd7d09SAndy Fiddaman 180*b4dd7d09SAndy Fiddaman # process reply 181*b4dd7d09SAndy Fiddaman parse_http_response httpresponse <&${netfd} 182*b4dd7d09SAndy Fiddaman response="${ cat_http_body "${httpresponse.transfer_encoding}" <&${netfd} ; }" 183*b4dd7d09SAndy Fiddaman 184*b4dd7d09SAndy Fiddaman # close connection 185*b4dd7d09SAndy Fiddaman redirect {netfd}<&- 186*b4dd7d09SAndy Fiddaman 187*b4dd7d09SAndy Fiddaman if (( httpresponse.statuscode >= 200 && httpresponse.statuscode <= 299 )) ; then 188*b4dd7d09SAndy Fiddaman # the statement below should really parse the XML... 189*b4dd7d09SAndy Fiddaman print -r -- "${response/~(Elr).*(\<url\>)(.*)(\<\/url\>).*/\2}" 190*b4dd7d09SAndy Fiddaman return 0 191*b4dd7d09SAndy Fiddaman else 192*b4dd7d09SAndy Fiddaman print -u2 -f $"tr.im response was (%s,%s):\n%s\n" "${httpresponse.statuscode}" "${httpresponse.statusmsg}" "${response}" 193*b4dd7d09SAndy Fiddaman return 1 194*b4dd7d09SAndy Fiddaman fi 195*b4dd7d09SAndy Fiddaman 196*b4dd7d09SAndy Fiddaman # not reached 197*b4dd7d09SAndy Fiddaman} 198*b4dd7d09SAndy Fiddaman 199*b4dd7d09SAndy Fiddamanfunction usage 200*b4dd7d09SAndy Fiddaman{ 201*b4dd7d09SAndy Fiddaman OPTIND=0 202*b4dd7d09SAndy Fiddaman getopts -a "${progname}" "${shtinyurl_usage}" OPT '-?' 203*b4dd7d09SAndy Fiddaman exit 2 204*b4dd7d09SAndy Fiddaman} 205*b4dd7d09SAndy Fiddaman 206*b4dd7d09SAndy Fiddaman# program start 207*b4dd7d09SAndy Fiddamanbuiltin basename 208*b4dd7d09SAndy Fiddamanbuiltin cat 209*b4dd7d09SAndy Fiddamanbuiltin date 210*b4dd7d09SAndy Fiddamanbuiltin uname 211*b4dd7d09SAndy Fiddaman 212*b4dd7d09SAndy Fiddamantypeset progname="${ basename "${0}" ; }" 213*b4dd7d09SAndy Fiddaman 214*b4dd7d09SAndy Fiddaman# HTTP protocol client identifer 215*b4dd7d09SAndy Fiddamantypeset -r http_user_agent="shtinyurl/ksh93 (2010-03-27; ${ uname -s -r -p ; })" 216*b4dd7d09SAndy Fiddaman 217*b4dd7d09SAndy Fiddamantypeset -r shtinyurl_usage=$'+ 218*b4dd7d09SAndy Fiddaman[-?\n@(#)\$Id: shtinyurl (Roland Mainz) 2010-03-27 \$\n] 219*b4dd7d09SAndy Fiddaman[-author?Roland Mainz <roland.mainz@nrubsig.org>] 220*b4dd7d09SAndy Fiddaman[+NAME?shtinyurl - create short alias URL from long URL] 221*b4dd7d09SAndy Fiddaman[+DESCRIPTION?\bshtinyurl\b is a small utility which passes a given URL 222*b4dd7d09SAndy Fiddaman to internet service which creates short aliases in the 223*b4dd7d09SAndy Fiddaman form of http://<servicename>/XXXXXXXX to redirect long URLs.] 224*b4dd7d09SAndy Fiddaman[+?The first arg \burl\b describes a long URL which is transformed into 225*b4dd7d09SAndy Fiddaman a tinyurl.com short alias.] 226*b4dd7d09SAndy Fiddaman[P:provider?Service provider (either \'tinyurl.com\' or \'tr.im\').]:[mode] 227*b4dd7d09SAndy Fiddaman 228*b4dd7d09SAndy Fiddamanurl 229*b4dd7d09SAndy Fiddaman 230*b4dd7d09SAndy Fiddaman[+SEE ALSO?\bksh93\b(1), \brssread\b(1), \bshtwitter\b(1), http://www.tinyurl.com, http://tr.im] 231*b4dd7d09SAndy Fiddaman' 232*b4dd7d09SAndy Fiddaman 233*b4dd7d09SAndy Fiddamantypeset service_provider="tr.im" 234*b4dd7d09SAndy Fiddaman 235*b4dd7d09SAndy Fiddamanwhile getopts -a "${progname}" "${shtinyurl_usage}" OPT ; do 236*b4dd7d09SAndy Fiddaman# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" 237*b4dd7d09SAndy Fiddaman case ${OPT} in 238*b4dd7d09SAndy Fiddaman P) service_provider="${OPTARG}" ;; 239*b4dd7d09SAndy Fiddaman *) usage ;; 240*b4dd7d09SAndy Fiddaman esac 241*b4dd7d09SAndy Fiddamandone 242*b4dd7d09SAndy Fiddamanshift $((OPTIND-1)) 243*b4dd7d09SAndy Fiddaman 244*b4dd7d09SAndy Fiddaman# expecting at least one more argument 245*b4dd7d09SAndy Fiddaman(( $# >= 1 )) || usage 246*b4dd7d09SAndy Fiddaman 247*b4dd7d09SAndy Fiddamantypeset url="$1" 248*b4dd7d09SAndy Fiddamanshift 249*b4dd7d09SAndy Fiddaman 250*b4dd7d09SAndy Fiddamancase "${service_provider}" in 251*b4dd7d09SAndy Fiddaman "tinyurl.com") 252*b4dd7d09SAndy Fiddaman request_tinyurl "${url}" 253*b4dd7d09SAndy Fiddaman exit $? 254*b4dd7d09SAndy Fiddaman ;; 255*b4dd7d09SAndy Fiddaman "tr.im") 256*b4dd7d09SAndy Fiddaman request_trimurl "${url}" 257*b4dd7d09SAndy Fiddaman exit $? 258*b4dd7d09SAndy Fiddaman ;; 259*b4dd7d09SAndy Fiddaman *) 260*b4dd7d09SAndy Fiddaman fatal_error "Unsupported service provider." 261*b4dd7d09SAndy Fiddamanesac 262*b4dd7d09SAndy Fiddaman 263*b4dd7d09SAndy Fiddaman# not reached 264*b4dd7d09SAndy Fiddaman 265*b4dd7d09SAndy Fiddaman# EOF. 266