package lucee.runtime.functions.system;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Map.Entry;
import lucee.commons.io.CharsetUtil;
import lucee.commons.io.res.util.ResourceUtil;
import lucee.commons.lang.CharSet;
import lucee.commons.lang.StringUtil;
import lucee.commons.lang.mimetype.ContentType;
import lucee.commons.net.HTTPUtil;
import lucee.commons.net.URLEncoder;
import lucee.loader.engine.CFMLEngine;
import lucee.runtime.CFMLFactoryImpl;
import lucee.runtime.PageContext;
import lucee.runtime.PageContextImpl;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.exp.FunctionException;
import lucee.runtime.exp.PageException;
import lucee.runtime.ext.function.Function;
import lucee.runtime.functions.other.CreatePageContext;
import lucee.runtime.listener.ApplicationContext;
import lucee.runtime.net.http.HttpServletResponseDummy;
import lucee.runtime.net.http.ReqRspUtil;
import lucee.runtime.op.Caster;
import lucee.runtime.op.Decision;
import lucee.runtime.thread.ThreadUtil;
import lucee.runtime.type.Collection;
import lucee.runtime.type.Collection.Key;
import lucee.runtime.type.KeyImpl;
import lucee.runtime.type.Struct;
import lucee.runtime.type.StructImpl;
import lucee.runtime.type.scope.Form;
import lucee.runtime.type.util.KeyConstants;
public class InternalRequest implements Function {
private static final long serialVersionUID = -8163856691035353577L;
public static final Key FILECONTENT_BYNARY = KeyImpl._const("filecontent_binary");
public static final Key STATUS_CODE = KeyImpl._const("status_code");
private static final Key CONTENT_TYPE = KeyImpl._const("content-type");
public static Struct call(final PageContext pc, String template, String method,
Struct urls,Struct forms, Struct cookies, Struct headers, Object body,String strCharset, boolean addToken) throws PageException {
// add token
if(addToken) {
//if(true) throw new ApplicationException("addtoken==true");
if(cookies==null) cookies=new StructImpl();
cookies.set(KeyConstants._cfid, pc.getCFID());
cookies.set(KeyConstants._cftoken, pc.getCFToken());
String jsessionid = pc.getJSessionId();
if(jsessionid!=null) cookies.set("jsessionid", jsessionid);
}
// charset
Charset reqCharset=StringUtil.isEmpty(strCharset)?pc.getWebCharset():CharsetUtil.toCharset(strCharset);
String ext=ResourceUtil.getExtension(template, null);
// welcome files
if(StringUtil.isEmpty(ext)) {
throw new FunctionException(pc,"Invoke",1,"url","welcome file listing not supported, please define the template name.");
}
// dialect
int dialect=((CFMLFactoryImpl)pc.getConfig().getFactory()).toDialect(ext,-1);
if(dialect==-1) dialect=pc.getCurrentTemplateDialect();
// CFMLEngine.DIALECT_LUCEE
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] _barr=null;
if(Decision.isBinary(body)) _barr=Caster.toBinary(body);
else if(body!=null) {
Charset cs=null;
// get charset
if(headers!=null) {
String strCT=Caster.toString(headers.get(CONTENT_TYPE),null);
if(strCT!=null) {
ContentType ct = HTTPUtil.toContentType(strCT, null);
if(ct!=null) {
String strCS = ct.getCharset();
if(!StringUtil.isEmpty(strCS))
cs=CharsetUtil.toCharSet(strCS, CharSet.UTF8).toCharset();
}
}
}
if(cs==null) cs=CharsetUtil.UTF8;
String str=Caster.toString(body);
_barr=str.getBytes(cs);
}
PageContextImpl _pc=createPageContext(pc, template, urls, cookies, headers, _barr, reqCharset, baos);
fillForm(_pc,forms);
Collection cookie,request,session=null;
int status;
long exeTime;
boolean isText=false;
Charset _charset=null;
try{
if(CFMLEngine.DIALECT_LUCEE==dialect)
_pc.execute(template, true, false);
else
_pc.executeCFML(template, true, false);
}
finally{
_pc.flush();
cookie=_pc.cookieScope().duplicate(false);
request=_pc.requestScope().duplicate(false);
session=sessionEnabled(_pc)?_pc.sessionScope().duplicate(false):null;
exeTime=System.currentTimeMillis()-pc.getStartTime();
//debugging=_pc.getDebugger().getDebuggingData(_pc).duplicate(false);
HttpServletResponseDummy rsp = (HttpServletResponseDummy) _pc.getHttpServletResponse();
// headers
Collection.Key name;
headers=new StructImpl();
Iterator<String> it = rsp.getHeaderNames().iterator();
java.util.Collection<String> values;
while(it.hasNext()){
name=KeyImpl.init(it.next());
values=rsp.getHeaders(name.getString());
if(values==null || values.size()==0) continue;
if(values.size()>1)
headers.set(name, Caster.toArray(values));
else
headers.set(name, values.iterator().next());
}
// status
status = rsp.getStatus();
ContentType ct = HTTPUtil.toContentType(rsp.getContentType(),null);
if(ct!=null){
isText = HTTPUtil.isTextMimeType(ct.getMimeType());
if(ct.getCharset()!=null) _charset=CharsetUtil.toCharset(ct.getCharset(),null);
}
releasePageContext(_pc,pc);
}
Struct rst=new StructImpl();
byte[] barr=baos.toByteArray();
if(isText) rst.set(KeyConstants._filecontent, new String(barr,_charset==null?reqCharset:_charset));
else rst.set(FILECONTENT_BYNARY,barr);
rst.set(KeyConstants._cookies, cookie);
rst.set(KeyConstants._request, request);
if(session!=null)rst.set(KeyConstants._session, session);
rst.set(KeyConstants._headers, headers);
//rst.put(KeyConstants._debugging, debugging);
rst.set(KeyConstants._executionTime, new Double(exeTime));
rst.set(KeyConstants._status, new Double(status));
rst.set(STATUS_CODE, new Double(status));
return rst;
}
private static boolean sessionEnabled(PageContextImpl pc) {
ApplicationContext ac = pc.getApplicationContext();
if(ac==null)return false;// this test properly is not necessary
return ac.hasName() && ac.isSetSessionManagement();
}
private static void fillForm(PageContextImpl _pc, Struct src) throws PageException {
if(src==null) return;
Iterator<Entry<Key, Object>> it = src.entryIterator();
Form trg = _pc.formScope();
Entry<Key, Object> e;
while(it.hasNext()) {
e = it.next();
trg.set(e.getKey(), e.getValue());
}
}
private static PageContextImpl createPageContext(PageContext pc, String template, Struct urls, Struct cookies, Struct headers, byte[] body, Charset charset, OutputStream os) throws PageException {
// query string | URL
Entry<Key, Object> e;
StringBuilder sbQS=new StringBuilder();
if(urls!=null) {
Iterator<Entry<Key, Object>> it = urls.entryIterator();
while(it.hasNext()) {
e = it.next();
if(sbQS.length()>0) sbQS.append('&');
sbQS.append(urlenc(e.getKey().getString(),charset));
sbQS.append('=');
sbQS.append(urlenc(Caster.toString(e.getValue()), charset));
}
}
return ThreadUtil.createPageContext(
pc.getConfig(),
os,
pc.getHttpServletRequest().getServerName(),
template,
sbQS.toString(),
CreatePageContext.toCookies(cookies),
CreatePageContext.toPair(headers,true),
body,
CreatePageContext.toPair(new StructImpl(),true),
CreatePageContext.castValuesToString(new StructImpl()),true,-1);
}
private static void releasePageContext(PageContext pc, PageContext oldPC) {
pc.flush();
oldPC.getConfig().getFactory().releaseLuceePageContext(pc, false);
ThreadLocalPageContext.release();
if(oldPC!=null)ThreadLocalPageContext.register(oldPC);
}
private static String urlenc(String str, Charset charset) throws PageException {
try{
if(!ReqRspUtil.needEncoding(str,false)) return str;
return URLEncoder.encode(str,charset);
}
catch(UnsupportedEncodingException uee){
throw Caster.toPageException(uee);
}
}
}