/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source 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. * * Resin Open Source 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, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.quercus.lib; import com.caucho.quercus.QuercusModuleException; import com.caucho.quercus.annotation.Optional; import com.caucho.quercus.annotation.Reference; import com.caucho.quercus.env.*; import com.caucho.quercus.module.AbstractQuercusModule; import com.caucho.util.Alarm; import com.caucho.util.L10N; import com.caucho.util.QDate; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; /** * PHP HTTP functions */ public class HttpModule extends AbstractQuercusModule { private static final L10N L = new L10N(HttpModule.class); private static ArrayList<String> getHeaders(Env env) { ArrayList<String> headers = (ArrayList) env.getSpecialValue("caucho.headers"); if (headers == null) { headers = new ArrayList<String>(); env.setSpecialValue("caucho.headers", headers); } return headers; } /** * Adds a header. */ public static Value header(Env env, StringValue headerStr, @Optional("true") boolean replace, @Optional long httpResponseCode) { HttpServletResponse res = env.getResponse(); if (res == null) { env.error(L.l("header requires an http context")); return NullValue.NULL; } String header = headerStr.toString(); int len = header.length(); if (header.startsWith("HTTP/")) { int p = header.indexOf(' '); int status = 0; int ch; for (; p < len && header.charAt(p) == ' '; p++) { } for (; p < len && '0' <= (ch = header.charAt(p)) && ch <= '9'; p++) { status = 10 * status + ch - '0'; } for (; p < len && header.charAt(p) == ' '; p++) { } if (status > 0) { res.setStatus(status, header.substring(p)); return NullValue.NULL; } } int colonIndex = header.indexOf(':'); if (colonIndex > 0) { String key = header.substring(0, colonIndex).trim(); String value = header.substring(colonIndex + 1).trim(); if (key.equalsIgnoreCase("Location")) { // do not use sendRedirect because sendRedirect commits the response, // preventing Wordpress from sending a second Location header that // replaces the previous one //res.sendRedirect(value); //return NullValue.NULL; res.setStatus(302, "Found"); } if (replace) { res.setHeader(key, value); ArrayList<String> headers = getHeaders(env); int regionEnd = colonIndex + 1; for (int i = 0; i < headers.size(); i++) { String compare = headers.get(i); if (compare.regionMatches(true, 0, header, 0, regionEnd)) { headers.remove(i); break; } } headers.add(header); } else { res.addHeader(key, value); getHeaders(env).add(header); } if (key.equalsIgnoreCase("Content-Type")) { String encoding = env.getOutputEncoding(); if (encoding != null) { if (value.indexOf("charset") < 0) { if (value.indexOf("text/") < 0) res.setCharacterEncoding(encoding); } else if ("".equals(res.getCharacterEncoding())) { // php/1b0d res.setCharacterEncoding(encoding); } } } } else { // Check for special headers that are not // colon separated "key: value" pairs. if (header.equals("Not Modified") || header.equals("No Content")) { // php/1b0(j|k|l|m) if (httpResponseCode != 0) res.setStatus((int) httpResponseCode, header); } } return NullValue.NULL; } /** * Return a list of the headers that have been sent or are ready to send. */ public static ArrayValue headers_list(Env env) { ArrayList<String> headersList = getHeaders(env); int size = headersList.size(); ArrayValueImpl headersArray = new ArrayValueImpl(size); for (int i = 0; i < size; i++) headersArray.put(headersList.get(i)); return headersArray; } /** * Return true if the headers have been sent. */ public static boolean headers_sent(Env env, @Optional @Reference Value file, @Optional @Reference Value line) { HttpServletResponse res = env.getResponse(); return res.isCommitted(); } /** * Sets a cookie */ public static boolean setcookie(Env env, String name, @Optional String value, @Optional long expire, @Optional String path, @Optional String domain, @Optional boolean secure, @Optional boolean httpOnly) { long now = env.getCurrentTime(); if (value == null || value.equals("")) value = ""; StringBuilder sb = new StringBuilder(); int len = value.length(); for (int i = 0; i < len; i++) { char ch = value.charAt(i); if ('0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '-' || ch == '.' || ch == '_') { sb.append(ch); } else if (ch == ' ') { sb.append('+'); } else { sb.append('%'); int d = (ch / 16) & 0xf; if (d < 10) sb.append((char) ('0' + d)); else sb.append((char) ('A' + d - 10)); d = ch & 0xf; if (d < 10) sb.append((char) ('0' + d)); else sb.append((char) ('A' + d - 10)); } } Cookie cookie = new Cookie(name, sb.toString()); int maxAge = 0; if (expire > 0) { maxAge = (int) (expire - now / 1000); if (maxAge > 0) cookie.setMaxAge(maxAge); else cookie.setMaxAge(0); //php/1b0i } if (path != null && ! path.equals("")) cookie.setPath(path); if (domain != null && ! domain.equals("")) cookie.setDomain(domain); if (secure) cookie.setSecure(true); env.getResponse().addCookie(cookie); // add to headers list StringBuilder cookieHeader = new StringBuilder(); cookieHeader.append("Set-Cookie: "); cookieHeader.append(cookie.getName()); cookieHeader.append("="); cookieHeader.append(cookie.getValue()); if (maxAge == 0) { cookieHeader.append("; expires=Thu, 01-Dec-1994 16:00:00 GMT"); } else { QDate date = env.getGmtDate(); date.setGMTTime(now + 1000L * (long) maxAge); cookieHeader.append("; expires="); cookieHeader.append(date.format("%a, %d-%b-%Y %H:%M:%S GMT")); } if (path != null && ! path.equals("")) { cookieHeader.append("; path="); cookieHeader.append(path); } if (domain != null && ! domain.equals("")) { cookieHeader.append("; domain="); cookieHeader.append(domain); } if (secure) cookieHeader.append("; secure"); getHeaders(env).add(cookieHeader.toString()); return true; } }