package org.w3c.jigsaw.frames;
import java.io.*;
import java.net.*;
import java.util.*;
import org.w3c.tools.codec.*;
import org.w3c.tools.sorter.*;
import org.w3c.tools.resources.*;
import org.w3c.tools.resources.event.*;
import org.w3c.jigsaw.http.* ;
import org.w3c.jigsaw.html.* ;
import org.w3c.www.mime.*;
import org.w3c.www.http.*;
import org.w3c.tools.crypt.Md5;
import org.w3c.tools.resources.ProtocolException;
import org.w3c.tools.resources.NotAProtocolException;
public class HTTPFrame extends ProtocolFrame {
protected static Class filterClass = null;
public static final int COND_FAILED = 1;
public static final int COND_OK = 2;
protected static HttpTokenList _allowed = null;
private static HttpTokenList _put_allowed = null;
private static HttpTokenList _browse_allowed = null;
private static HttpTokenList _accept_ranges = null;
static {
String str_allowed[] = { "GET", "HEAD", "OPTIONS", "TRACE"};
_allowed = HttpFactory.makeStringList(str_allowed);
String str_allow[] = { "HEAD" , "GET" , "PUT" , "OPTIONS", "TRACE" };
_put_allowed = HttpFactory.makeStringList(str_allow);
String str_all[] = { "HEAD" , "GET" , "BROWSE" , "OPTIONS","TRACE" };
_browse_allowed = HttpFactory.makeStringList(str_allow);
String accept_ranges[] = { "bytes" };
_accept_ranges = HttpFactory.makeStringList(accept_ranges);
}
protected HttpTokenList allowed = _allowed;
protected static int ATTR_QUALITY = -1 ;
protected static int ATTR_TITLE = -1 ;
protected static int ATTR_CONTENT_LANGUAGE = -1 ;
protected static int ATTR_CONTENT_ENCODING = -1 ;
protected static int ATTR_CONTENT_TYPE = -1 ;
protected static int ATTR_CONTENT_LENGTH = -1 ;
protected static int ATTR_ICON = -1 ;
protected static int ATTR_MAXAGE = -1 ;
protected static int ATTR_MD5 = -1;
protected static int ATTR_PUTABLE = -1 ;
protected static int ATTR_RELOCATE = -1 ;
protected static int ATTR_INDEX = -1 ;
protected static int ATTR_ICONDIR = -1 ;
protected static int ATTR_BROWSABLE = -1 ;
protected static int ATTR_STYLE_LINK = -1 ;
static {
Attribute a = null ;
Class cls = null ;
try {
filterClass =
Class.forName("org.w3c.tools.resources.ResourceFilter");
} catch (Exception ex) {
throw new RuntimeException("No ResourceFilter class found.");
}
try {
cls = Class.forName("org.w3c.jigsaw.frames.HTTPFrame") ;
} catch (Exception ex) {
ex.printStackTrace() ;
System.exit(1) ;
}
a = new DoubleAttribute("quality"
, new Double(1.0)
, Attribute.EDITABLE);
ATTR_QUALITY = AttributeRegistry.registerAttribute(cls, a) ;
a = new StringAttribute("title"
, null
, Attribute.EDITABLE) ;
ATTR_TITLE = AttributeRegistry.registerAttribute(cls, a) ;
a = new LanguageAttribute("content-language"
, null
, Attribute.EDITABLE) ;
ATTR_CONTENT_LANGUAGE = AttributeRegistry.registerAttribute(cls,a);
a = new EncodingAttribute("content-encoding"
, null
, Attribute.EDITABLE) ;
ATTR_CONTENT_ENCODING = AttributeRegistry.registerAttribute(cls,a);
a = new MimeTypeAttribute("content-type"
, MimeType.TEXT_PLAIN
, Attribute.EDITABLE) ;
ATTR_CONTENT_TYPE = AttributeRegistry.registerAttribute(cls,a);
a = new IntegerAttribute("content-length"
, null
, Attribute.COMPUTED);
ATTR_CONTENT_LENGTH = AttributeRegistry.registerAttribute(cls,a);
a = new StringAttribute("icon"
, null
, Attribute.EDITABLE) ;
ATTR_ICON = AttributeRegistry.registerAttribute(cls, a) ;
a = new LongAttribute("maxage"
, null
, Attribute.EDITABLE) ;
ATTR_MAXAGE = AttributeRegistry.registerAttribute(cls, a) ;
a = new BooleanAttribute("send-md5"
, Boolean.FALSE
, Attribute.EDITABLE);
ATTR_MD5 = AttributeRegistry.registerAttribute(cls, a) ;
a = new BooleanAttribute("putable"
, Boolean.FALSE
, Attribute.EDITABLE) ;
ATTR_PUTABLE = AttributeRegistry.registerAttribute(cls, a) ;
a = new BooleanAttribute("relocate"
, Boolean.TRUE
, Attribute.EDITABLE);
ATTR_RELOCATE = AttributeRegistry.registerAttribute(cls, a) ;
a = new StringAttribute("index"
, null
, Attribute.EDITABLE) ;
ATTR_INDEX = AttributeRegistry.registerAttribute(cls, a) ;
a = new StringAttribute("icondir"
, null
, Attribute.EDITABLE) ;
ATTR_ICONDIR = AttributeRegistry.registerAttribute(cls,a);
a = new BooleanAttribute("browsable"
, Boolean.FALSE
, Attribute.EDITABLE) ;
ATTR_BROWSABLE = AttributeRegistry.registerAttribute(cls, a) ;
a = new StringAttribute("style-sheet-link"
, null
, Attribute.EDITABLE) ;
ATTR_STYLE_LINK = AttributeRegistry.registerAttribute(cls, a) ;
}
protected DirectoryResource dresource = null;
protected FileResource fresource = null;
public void registerResource(FramedResource resource) {
super.registerResource(resource);
if (resource instanceof FileResource)
fresource = (FileResource) resource;
else if (resource instanceof DirectoryResource)
dresource = (DirectoryResource) resource;
}
public FileResource getFileResource() {
return fresource;
}
public DirectoryResource getDirectoryResource() {
return dresource;
}
@param the
public void registerOtherResource(FramedResource resource) {
super.registerResource(resource);
dresource = null;
fresource = null;
}
HttpMimeType contenttype = null;
HttpInteger contentlength = null;
HttpDate lastmodified = null;
HttpTokenList contentencoding = null;
HttpTokenList contentlanguage = null;
HttpEntityTag etag = null;
HttpString md5Digest = null;
@return
public String getHelpURL() {
httpd server = (httpd) getServer();
if ( server == null )
return null;
String docurl = server.getDocumentationURL();
if ( docurl == null )
return null;
return docurl + "/" + getClass().getName() + ".html";
}
@param topic@return
public String getHelpURL(String topic) {
httpd server = (httpd) getServer();
if ( server == null )
return null;
String docurl = server.getDocumentationURL();
if ( docurl == null )
return null;
Class defines = AttributeRegistry.getAttributeClass(getClass(), topic);
if ( defines != null )
return docurl + "/" + defines.getName() + ".html";
return null;
}
@return
private HttpString getMd5Digest() {
if (md5Digest != null)
return md5Digest;
Resource r = getResource();
if (r instanceof FileResource) {
try {
Md5 md5 = new Md5 (
new FileInputStream(((FileResource)r).getFile()));
String s = null;
try {
byte b[] = md5.getDigest();
Base64Encoder b64;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
b64 = new Base64Encoder(new ByteArrayInputStream(b), bos);
b64.process();
s = bos.toString();
md5Digest = HttpFactory.makeString(s);
} catch (Exception mdex) {
md5Digest = null;
}
return md5Digest;
} catch (FileNotFoundException ex) {
md5Digest = null;
}
}
return null;
}
public void attributeChanged(AttributeChangedEvent evt) {
super.attributeChanged(evt);
String name = evt.getAttribute().getName();
if (name.equals("file-stamp")) {
etag = null;
lastmodified = null;
md5Digest = null;
} else if (name.equals("file-length")) {
setValue(ATTR_CONTENT_LENGTH, evt.getNewValue());
} else if (name.equals("last-modified")) {
setValue(ATTR_LAST_MODIFIED, evt.getNewValue());
} else {
lastmodified = null;
}
}
@param idx@param value
public synchronized void setValue(int idx, Object value) {
super.setValue(idx, value);
if (idx == ATTR_CONTENT_TYPE)
contenttype = null;
if (idx == ATTR_CONTENT_LENGTH)
contentlength = null;
if ( idx == ATTR_CONTENT_ENCODING )
contentencoding = null;
if ( idx == ATTR_CONTENT_LANGUAGE )
contentlanguage = null;
if ( idx == ATTR_PUTABLE) {
if (fresource != null) {
if (value == Boolean.TRUE)
allowed = _put_allowed;
else
allowed = _allowed;
}
}
if (idx == ATTR_MD5) {
md5Digest = null; }
lastmodified = null;
}
@return
public URL getURL(Request request) {
try {
return new URL(request.getURL(), resource.getURLPath());
} catch (MalformedURLException ex) {
throw new RuntimeException("unable to build "+
getURLPath()+
" full URL, from server "+
getServer().getURL());
}
}
@return
public double getQuality() {
return getDouble(ATTR_QUALITY, -1.0) ;
}
@return
public String getTitle() {
return getString(ATTR_TITLE, null) ;
}
@return
public String getContentLanguage() {
return (String) getValue(ATTR_CONTENT_LANGUAGE, null) ;
}
@return
public String getContentEncoding() {
String def = (String) attributes[ATTR_CONTENT_ENCODING].getDefault();
System.out.println("Default ["+def+"]");
String s = (String) getString (ATTR_CONTENT_ENCODING, def) ;
System.out.println("Defaulted to ["+s+"]");
return (String) getString (ATTR_CONTENT_ENCODING, def) ;
}
@return
public MimeType getContentType() {
return (MimeType) getValue(ATTR_CONTENT_TYPE, null);
}
@return
public int getContentLength() {
return getInt(ATTR_CONTENT_LENGTH, -1) ;
}
public String getIcon() {
return getString(ATTR_ICON, null) ;
}
public long getMaxAge() {
return getLong(ATTR_MAXAGE, (long) -1) ;
}
protected boolean acceptRanges = false;
public boolean getPutableFlag() {
return getBoolean(ATTR_PUTABLE, false) ;
}
public boolean getMD5Flag() {
return getBoolean(ATTR_MD5, false) ;
}
@param request@param r@return
public Reply handleRangeRequest(Request request, HttpRange r)
throws ProtocolException
{
HttpEntityTag t = request.getIfRange();
if ( t != null ) {
if (t.isWeak() || ! t.getTag().equals(etag.getTag()))
return null;
}
int cl = getContentLength();
int fb = r.getFirstPosition();
int lb = r.getLastPosition();
int sz;
if (fb > cl-1) { HttpContentRange cr = HttpFactory.makeContentRange("bytes", 0,
cl - 1, cl);
Reply rr;
rr = createDefaultReply(request,
HTTP.REQUESTED_RANGE_NOT_SATISFIABLE);
rr.setContentLength(-1);
rr.setHeaderValue(rr.H_CONTENT_RANGE, cr);
if (getMD5Flag())
rr.setContentMD5(null);
return rr;
}
if ((fb < 0) && (lb >= 0)) { if (lb >= cl) lb = cl;
sz = lb;
fb = cl - lb;
lb = cl - 1;
} else if (lb < 0) { lb = cl-1;
sz = lb-fb+1;
} else { if (lb >= cl) lb = cl-1;
sz = lb-fb+1;
}
if ((fb < 0) || (lb < 0) || (fb <= lb)) {
HttpContentRange cr = null;
fb = (fb < 0) ? 0 : fb;
lb = ((lb > cl) || (lb < 0)) ? cl : lb;
cr = HttpFactory.makeContentRange("bytes", fb, lb, cl);
Reply rr = createDefaultReply(request, HTTP.PARTIAL_CONTENT);
try { if (getMD5Flag()) {
String s = null;
try {
ByteRangeOutputStream br;
br = new ByteRangeOutputStream(fresource.getFile(),
fb, lb+1);
Md5 md5 = new Md5 (br);
byte b[] = md5.getDigest();
Base64Encoder b64;
ByteArrayOutputStream bs = new ByteArrayOutputStream();
b64 = new Base64Encoder(new ByteArrayInputStream(b),
bs);
b64.process();
s = bs.toString();
} catch (Exception md_ex) {
}
if (s == null)
rr.setContentMD5(null);
else
rr.setContentMD5(s);
}
rr.setContentLength(sz);
rr.setHeaderValue(rr.H_CONTENT_RANGE, cr);
rr.setStream(new ByteRangeOutputStream(fresource.getFile(),
fb,
lb+1));
return rr;
} catch (IOException ex) {
}
}
return null;
}
public boolean getBrowsableFlag() {
return getBoolean (ATTR_BROWSABLE, false) ;
}
public String getStyleSheetURL() {
return getString (ATTR_STYLE_LINK, null);
}
protected HtmlGenerator listing = null ;
protected long listing_stamp = -1 ;
private String getUnextendedName(String name) {
int strlen = name.length() ;
for (int i = 0 ; i < strlen ; i++) {
if ( name.charAt(i) == '.' ) {
if ( i == 0 )
return null ;
return name.substring(0, i) ;
}
}
return null ;
}
public String getIconDirectory() {
return getString(ATTR_ICONDIR, "/icons") ;
}
@return
public boolean getRelocateFlag() {
return getBoolean(ATTR_RELOCATE, true) ;
}
@return
public String getIndex() {
return (String) getValue(ATTR_INDEX, null) ;
}
@param g
protected void addStyleSheet(HtmlGenerator g) {
String css_url = getStyleSheetURL();
if (css_url != null) {
g.addLink( new HtmlLink("STYLESHEET",
css_url,
MimeType.TEXT_CSS));
}
}
@param request@exception ProtocolException
public synchronized Reply getDirectoryListing(Request request)
throws ProtocolException, NotAProtocolException
{
if (dresource == null)
throw new NotAProtocolException("this frame is not attached to a "+
"DirectoryResource. ("+
resource.getIdentifier()+")");
if (! dresource.getDirectory().exists()) {
String msg = dresource.getIdentifier()+
": deleted, removing the DirectoryResource";
getServer().errlog(dresource, msg);
try {
dresource.delete();
} catch (MultipleLockException ex) {
}
Reply error = request.makeReply(HTTP.NOT_FOUND) ;
error.setContent ("<h1>Document not found</h1>"+
"<p>The document "+
request.getURL()+
" is indexed but not available."+
"<p>The server is misconfigured.") ;
throw new HTTPException (error) ;
}
if ((listing == null)
|| (dresource.getDirectory().lastModified() > listing_stamp)
|| (dresource.getLastModified() > listing_stamp)
|| (getLastModified() > listing_stamp)) {
Class http_class = null;
try {
http_class = Class.forName("org.w3c.jigsaw.frames.HTTPFrame");
} catch (ClassNotFoundException ex) {
http_class = null;
}
Enumeration enum =
dresource.enumerateResourceIdentifiers() ;
Vector resources = Sorter.sortStringEnumeration(enum) ;
HtmlGenerator g =
new HtmlGenerator("Directory of "+
dresource.getIdentifier());
addStyleSheet(g);
g.append("<h1>"+dresource.getIdentifier()+"</h1>");
if ( dresource.getParent() != null )
g.append("<p><a href=\"..\">Parent</a><br>");
for (int i = 0 ; i < resources.size() ; i++) {
String name = (String) resources.elementAt(i);
ResourceReference rr = null;
rr = dresource.lookup(name);
FramedResource resource = null;
if (rr != null) {
try {
resource = (FramedResource) rr.lock();
HTTPFrame itsframe = null;
if (http_class != null)
itsframe =
(HTTPFrame) resource.getFrame(http_class);
if (itsframe != null) {
String icon = itsframe.getIcon() ;
if ( icon != null )
g.append("<img src=\""+
getIconDirectory() +"/" + icon+
"\">");
g.append("<a href=\""
, resource.getURLPath()
, "\">"+name+"</a>");
String title = itsframe.getTitle();
if ( title != null )
g.append(" "+title);
g.append("<br>");
} else {
g.append(name+" (<i>Not available via HTTP.</i>)");
g.append("<br>");
}
} catch (InvalidResourceException ex) {
g.append(name+
" cannot be loaded (server misconfigured)");
g.append("<br>");
continue;
} finally {
rr.unlock();
}
}
}
g.close() ;
listing_stamp = getLastModified() ;
listing = g ;
} else if ( checkIfModifiedSince(request) == COND_FAILED ) {
Reply reply = createDefaultReply(request, HTTP.NOT_MODIFIED) ;
reply.setContentMD5(null);
return reply;
}
Reply reply = createDefaultReply(request, HTTP.OK) ;
reply.setLastModified(listing_stamp) ;
reply.setStream(listing) ;
return reply ;
}
protected void updateCachedHeaders() {
if ( contenttype == null )
contenttype = HttpFactory.makeMimeType(getContentType());
if (contentlength == null) {
int cl = -1;
if (fresource != null)
cl = fresource.getFileLength();
if ( cl >= 0 ) {
setValue(ATTR_CONTENT_LENGTH, new Integer(cl));
contentlength = HttpFactory.makeInteger(cl);
}
}
if ( lastmodified == null ) {
long lm = getLastModified();
if ( lm > 0 )
lastmodified = HttpFactory.makeDate(getLastModified());
}
if (definesAttribute(ATTR_CONTENT_ENCODING) &&(contentencoding==null))
contentencoding = HttpFactory.makeStringList(getContentEncoding());
if (definesAttribute(ATTR_CONTENT_LANGUAGE) &&(contentlanguage==null))
contentlanguage = HttpFactory.makeStringList(getContentLanguage());
if (fresource != null) {
if ( etag == null ) {
long lstamp = fresource.getFileStamp();
if ( lstamp >= 0L ) {
String soid = Integer.toString(getOid(), 32);
String stamp = Long.toString(lstamp, 32);
etag = HttpFactory.makeETag(false, soid+":"+stamp);
}
}
if (getMD5Flag() && (md5Digest == null)) {
getMd5Digest();
}
}
}
@param request@return
public Reply createDefaultReply(Request request, int status) {
Reply reply = request.makeReply(status);
updateCachedHeaders();
if ( status != HTTP.NOT_MODIFIED ) {
if ( contentlength != null )
reply.setHeaderValue(Reply.H_CONTENT_LENGTH, contentlength);
if ( contenttype != null )
reply.setHeaderValue(Reply.H_CONTENT_TYPE, contenttype);
if ( lastmodified != null )
reply.setHeaderValue(Reply.H_LAST_MODIFIED, lastmodified);
if ( contentencoding != null ) {
System.out.println("Content Encoding [" + contentencoding +"]");
reply.setHeaderValue(Reply.H_CONTENT_ENCODING,contentencoding);
}
if ( contentlanguage != null )
reply.setHeaderValue(Reply.H_CONTENT_LANGUAGE,contentlanguage);
}
long maxage = getMaxAge();
if ( maxage >= 0 ) {
if (reply.getMajorVersion() >= 1 ) {
if (reply.getMinorVersion() >= 1) {
reply.setMaxAge((int) (maxage / 1000));
}
long expires = (System.currentTimeMillis()
+ ((maxage == 0) ? -1000 : maxage));
reply.setExpires(expires);
}
}
reply.setDate((System.currentTimeMillis() / 1000L) * 1000L);
if (fresource != null) {
if ( etag != null )
reply.setHeaderValue(reply.H_ETAG, etag);
if ( acceptRanges )
reply.setHeaderValue(reply.H_ACCEPT_RANGES, _accept_ranges);
if ( getMD5Flag()) {
reply.setHeaderValue(reply.H_CONTENT_MD5, getMd5Digest());
}
}
return reply;
}
@param request@return
public int checkIfMatch(Request request) {
if (fresource != null) {
HttpEntityTag tags[] = request.getIfMatch();
if ( tags != null ) {
if ( etag != null ) {
for (int i = 0 ; i < tags.length ; i++) {
HttpEntityTag t = tags[i];
if ((!t.isWeak()) && t.getTag().equals(etag.getTag()))
return COND_OK;
}
}
return COND_FAILED;
}
}
return 0;
}
@param request@return
public int checkIfNoneMatch(Request request) {
if (fresource != null) {
HttpEntityTag tags[] = request.getIfNoneMatch();
if ( tags != null ) {
if ( etag == null )
return COND_OK;
for (int i = 0 ; i < tags.length ; i++) {
HttpEntityTag t = tags[i];
if (( ! t.isWeak()) && t.getTag().equals(etag.getTag()))
return COND_FAILED;
}
return COND_OK;
}
}
return 0;
}
@param request@return
public int checkIfModifiedSince(Request request) {
long ims = request.getIfModifiedSince();
if (dresource != null) {
if (ims >= 0)
return (((listing_stamp > 0) && (listing_stamp - 1000 <= ims))
? COND_FAILED
: COND_OK);
} else if (fresource != null) {
long cmt = getLastModified();
if ( ims >= 0 )
return ((cmt > 0) && (cmt - 1000 <= ims))
? COND_FAILED : COND_OK;
}
return 0;
}
@param request@return
public int checkIfUnmodifiedSince(Request request) {
if (fresource != null) {
long iums = request.getIfUnmodifiedSince();
long cmt = getLastModified();
if ( iums >= 0 )
return ((cmt > 0) && (cmt - 1000) >= iums)
? COND_FAILED : COND_OK;
}
return 0;
}
public boolean lookup(LookupState ls, LookupResult lr)
throws ProtocolException
{
RequestInterface req = ls.getRequest();
if (! checkRequest(req))
return false;
if (lookupFilters(ls,lr))
return true;
return lookupResource(ls,lr);
}
protected boolean lookupResource(LookupState ls, LookupResult lr)
throws ProtocolException
{
if (fresource != null) {
return lookupFile(ls,lr);
} else if (dresource != null) {
return lookupDirectory(ls,lr);
} else {
return lookupOther(ls,lr);
}
}
protected boolean lookupFilters(LookupState ls, LookupResult lr)
throws ProtocolException
{
ResourceFilter filters[] = getFilters();
if ( filters != null ) {
lr.addFilters(filters);
for (int i = 0 ; i < filters.length ; i++) {
if ( filters[i] == null )
continue;
if ( filters[i].lookup(ls, lr) )
return true;
}
}
return false;
}
protected boolean lookupDirectory(LookupState ls, LookupResult lr)
throws ProtocolException
{
if ((ls.hasMoreComponents()) && getPutableFlag()) {
Request request = (Request) ls.getRequest() ;
if ((request == null) || request.getMethod().equals("PUT")) {
String name = ls.peekNextComponent() ;
ResourceReference rr = dresource.lookup(name);
if ((rr == null) && (dresource.getExtensibleFlag())) {
if (ls.countRemainingComponents() == 1)
rr = dresource.createResource(name, request);
else
rr = dresource.createDirectoryResource(name);
if (rr == null) {
Reply error =
request.makeReply(HTTP.UNSUPPORTED_MEDIA_TYPE);
error.setContent(
"Failed to create resource "+
name +" : "+
"Unable to create the appropriate file:"+
request.getURLPath()+
" this media type is not supported");
throw new HTTPException (error);
}
} else if (rr == null) {
Reply error = request.makeReply(HTTP.FORBIDDEN) ;
error.setContent("You are not allowed to create resource "+
name +" : "+
dresource.getIdentifier()+
" is not extensible.");
throw new HTTPException (error);
}
}
}
if ( super.lookup(ls, lr) ) {
if ( ! ls.isDirectory() && ! ls.isInternal() ) {
Request request = (Request)ls.getRequest() ;
if ( request == null ) {
lr.setTarget(null);
return true;
}
URL url = null;
try {
url = (ls.hasRequest()
? getURL(request)
: new URL(getServer().getURL(),
resource.getURLPath()));
} catch (MalformedURLException ex) {
getServer().errlog(this, "unable to build full URL.");
throw new HTTPException("Internal server error");
}
String msg = "Invalid requested URL: the directory resource "+
" you are trying to reach is available only through "+
" its full URL: <a href=\""+
url + "\">" + url + "</a>.";
if ( getRelocateFlag() ) {
Reply reloc = request.makeReply(HTTP.FOUND);
reloc.setContent(msg) ;
reloc.setLocation(url);
lr.setTarget(null);
lr.setReply(reloc);
return true;
} else {
Reply error = request.makeReply(HTTP.NOT_FOUND) ;
error.setContent(msg) ;
lr.setTarget(null);
lr.setReply(error);
return true;
}
} else if ( ! ls.isInternal() ) {
String index = getIndex();
if ( index != null && index.length() > 0) {
DirectoryResource dir = (DirectoryResource) resource;
ResourceReference rr = dir.lookup(index);
if (rr != null) {
try {
FramedResource rindex = (FramedResource) rr.lock();
return rindex.lookup(ls,lr);
} catch (InvalidResourceException ex) {
} finally {
rr.unlock();
}
}
}
}
return true;
}
return false;
}
protected boolean lookupFile(LookupState ls, LookupResult lr)
throws ProtocolException
{
return super.lookup(ls,lr);
}
protected boolean lookupOther(LookupState ls, LookupResult lr)
throws ProtocolException
{
return super.lookup(ls,lr);
}
public boolean checkRequest(RequestInterface request) {
return ((request == null)
? true
:(request instanceof org.w3c.jigsaw.http.Request));
}
protected ReplyInterface performFrames(RequestInterface request)
throws ProtocolException, NotAProtocolException
{
return super.performFrames(request);
}
public ReplyInterface perform(RequestInterface req)
throws ProtocolException, NotAProtocolException
{
ReplyInterface repi = super.perform(req);
if (repi != null)
return repi;
if (! checkRequest(req))
return null;
Reply reply = null;
Request request = (Request) req;
String method = request.getMethod () ;
if ( method.equals("GET") ) {
reply = get(request) ;
} else if ( method.equals("HEAD") ) {
reply = head(request) ;
} else if ( method.equals("POST") ) {
reply = post(request) ;
} else if ( method.equals("PUT") ) {
reply = put(request) ;
} else if ( method.equals("OPTIONS") ) {
reply = options(request);
} else if ( method.equals("DELETE") ) {
reply = delete(request) ;
} else if ( method.equals("LINK") ) {
reply = link(request) ;
} else if ( method.equals("UNLINK") ) {
reply = unlink(request) ;
} else if ( method.equals("TRACE") ) {
reply = trace(request) ;
} else {
reply = extended(request) ;
}
return reply;
}
@param request@exception ProtocolException@exception NotAProtocolException
public Reply get(Request request)
throws ProtocolException, NotAProtocolException
{
if (dresource != null) {
return getDirectoryResource(request) ;
} else if (fresource != null) {
return getFileResource(request);
} else {
return getOtherResource(request);
}
}
protected Reply getOtherResource(Request request)
throws ProtocolException, NotAProtocolException
{
Reply error = request.makeReply(HTTP.NOT_IMPLEMENTED) ;
error.setContent("Method GET not implemented.") ;
throw new HTTPException (error) ;
}
@param request@return
protected Reply createFileReply(Request request)
throws ProtocolException, NotAProtocolException
{
File file = fresource.getFile() ;
Reply reply = null;
HttpRange ranges[] = request.getRange();
if ((ranges != null) && (ranges.length == 1)) {
Reply rangereply = handleRangeRequest(request, ranges[0]);
if ( rangereply != null )
return rangereply;
}
reply = createDefaultReply(request, HTTP.OK) ;
try {
reply.setStream(new FileInputStream(file));
} catch (IOException ex) {
}
return reply ;
}
protected Reply getFileResource(Request request)
throws ProtocolException, NotAProtocolException
{
if (fresource == null)
throw new NotAProtocolException("this frame is not attached to a "+
"FileResource. ("+
resource.getIdentifier()+")");
Reply reply = null;
File file = fresource.getFile() ;
fresource.checkContent();
updateCachedHeaders();
if ( checkIfMatch(request) == COND_FAILED ) {
reply = request.makeReply(HTTP.PRECONDITION_FAILED);
reply.setContent("Pre-conditions failed.");
reply.setContentMD5(null);
return reply;
}
if ( checkIfNoneMatch(request) == COND_FAILED ) {
reply = createDefaultReply(request, HTTP.NOT_MODIFIED);
reply.setContentMD5(null);
return reply;
}
if ( checkIfModifiedSince(request) == COND_FAILED ) {
reply = createDefaultReply(request, HTTP.NOT_MODIFIED);
reply.setContentMD5(null);
return reply;
}
if ( checkIfUnmodifiedSince(request) == COND_FAILED ) {
reply = request.makeReply(HTTP.PRECONDITION_FAILED);
reply.setContent("Pre-conditions failed.");
reply.setContentMD5(null);
return reply;
}
if ( file.exists() ) {
return createFileReply(request);
} else {
boolean extensible = false;
ResourceReference rr = fresource.getParent();
ResourceReference rrtemp = null;
Resource p = null;
while ( true ) {
try {
if (rr == null)
break;
p = rr.lock();
if (p instanceof DirectoryResource) {
extensible =
((DirectoryResource)p).getExtensibleFlag();
break;
}
rrtemp = p.getParent();
} catch (InvalidResourceException ex) {
break;
} finally {
if (rr != null)
rr.unlock();
}
rr = rrtemp;
}
if (extensible) {
String msg = fresource.getFile()+
": deleted, removing the FileResource.";
getServer().errlog(fresource, msg);
try {
fresource.delete();
} catch (MultipleLockException ex) {
Reply error = request.makeReply(HTTP.NOT_FOUND) ;
error.setContentMD5(null); error.setContent ("<h1>Document not found</h1>"+
"<p>The document "+
request.getURL()+
" is indexed but not available."+
"<p>"+ex.getMessage()+
"<p>The server is misconfigured.") ;
throw new HTTPException (error) ;
}
}
Reply error = request.makeReply(HTTP.NOT_FOUND) ;
error.setContentMD5(null);
error.setContent ("<h1>Document not found</h1>"+
"<p>The document "+
request.getURL()+
" is indexed but not available."+
"<p>The server is misconfigured.") ;
throw new HTTPException (error) ;
}
}
protected Reply getDirectoryResource(Request request)
throws ProtocolException, NotAProtocolException
{
return getDirectoryListing(request) ;
}
@param request@exception ProtocolException@exception NotAProtocolException
public Reply head(Request request)
throws ProtocolException, NotAProtocolException
{
if (dresource != null) {
return headDirectoryResource(request);
} else if (fresource != null) {
return headFileResource(request);
} else {
return headOtherResource(request);
}
}
protected Reply headOtherResource(Request request)
throws ProtocolException, NotAProtocolException
{
Reply reply = null;
reply = getOtherResource(request) ;
reply.setStream((InputStream) null);
return reply;
}
protected Reply headDirectoryResource(Request request)
throws ProtocolException, NotAProtocolException
{
Reply reply = null;
reply = getDirectoryResource(request) ;
reply.setStream((InputStream) null);
return reply;
}
protected Reply headFileResource(Request request)
throws ProtocolException, NotAProtocolException
{
if (fresource == null)
throw new NotAProtocolException("this frame is not attached to a "+
"FileResource. ("+
resource.getIdentifier()+")");
Reply reply = null;
fresource.checkContent();
updateCachedHeaders();
if ( checkIfMatch(request) == COND_FAILED ) {
Reply r = request.makeReply(HTTP.PRECONDITION_FAILED);
r.setContent("Pre-conditions failed.");
return r;
}
if ( checkIfNoneMatch(request) == COND_FAILED )
return createDefaultReply(request, HTTP.NOT_MODIFIED);
if ( checkIfModifiedSince(request) == COND_FAILED )
return createDefaultReply(request, HTTP.NOT_MODIFIED);
if ( checkIfUnmodifiedSince(request) == COND_FAILED ) {
Reply r = request.makeReply(HTTP.PRECONDITION_FAILED);
r.setContent("Pre-conditions failed.");
return r;
}
if (! fresource.getFile().exists()) {
boolean extensible = false;
ResourceReference rr = fresource.getParent();
ResourceReference rrtemp = null;
Resource p = null;
while ( true ) {
try {
if (rr == null)
break;
p = rr.lock();
if (p instanceof DirectoryResource)
extensible =
((DirectoryResource)p).getExtensibleFlag();
rrtemp = p.getParent();
} catch (InvalidResourceException ex) {
break;
} finally {
if (rr != null)
rr.unlock();
}
rr = rrtemp;
}
if (extensible) {
String msg = fresource.getFile()+
": deleted, removing the FileResource.";
getServer().errlog(fresource, msg);
try {
fresource.delete();
} catch (MultipleLockException ex) {
Reply error = request.makeReply(HTTP.NOT_FOUND) ;
error.setContent ("<h1>Document not found</h1>"+
"<p>The document "+
request.getURL()+
" is indexed but not available."+
"<p>"+ex.getMessage()+
"<p>The server is misconfigured.") ;
throw new HTTPException (error) ;
}
}
Reply error = request.makeReply(HTTP.NOT_FOUND) ;
error.setContent ("<h1>Document not found</h1>"+
"<p>The document "+
request.getURL()+
" is indexed but not available."+
"<p>The server is misconfigured.") ;
throw new HTTPException (error) ;
}
return createDefaultReply(request, HTTP.OK);
}
@param request@exception ProtocolException@exception NotAProtocolException
public Reply post(Request request)
throws ProtocolException, NotAProtocolException
{
Reply error = request.makeReply(HTTP.NOT_ALLOWED) ;
if ( allowed != null )
error.setHeaderValue(Reply.H_ALLOW, allowed);
error.setContent("Method POST not allowed on this resource.") ;
throw new HTTPException (error) ;
}
@param request@exception ProtocolException@exception NotAProtocolException
public Reply put(Request request)
throws ProtocolException, NotAProtocolException
{
if (fresource != null) {
return putFileResource(request);
} else {
return putOtherResource(request);
}
}
protected Reply putOtherResource(Request request)
throws ProtocolException
{
Reply error = request.makeReply(HTTP.NOT_IMPLEMENTED) ;
error.setContent("Method PUT not implemented.") ;
throw new HTTPException (error) ;
}
protected Reply putFileResource(Request request)
throws ProtocolException, NotAProtocolException
{
Reply reply = null;
int status = HTTP.OK;
fresource.checkContent();
updateCachedHeaders();
if ( ! getPutableFlag() ) {
Reply error = request.makeReply(HTTP.NOT_ALLOWED) ;
error.setContent("Method PUT not allowed.") ;
throw new HTTPException (error) ;
}
if ((checkIfMatch(request) == COND_FAILED)
|| (checkIfNoneMatch(request) == COND_FAILED)
|| (checkIfModifiedSince(request) == COND_FAILED)
|| (checkIfUnmodifiedSince(request) == COND_FAILED)) {
Reply r = request.makeReply(HTTP.PRECONDITION_FAILED);
r.setContent("Pre-condition failed.");
return r;
}
InputStream in = null;
try {
in = request.getInputStream();
if ( in == null ) {
Reply error = request.makeReply(HTTP.BAD_REQUEST) ;
error.setContent ("<p>Request doesn't have a valid content.");
throw new HTTPException (error) ;
}
} catch (IOException ex) {
throw new ClientException(request.getClient(), ex);
}
if ( request.hasContentRange() ) {
Reply error = request.makeReply(HTTP.BAD_REQUEST);
error.setContent("partial PUT not supported.");
throw new HTTPException(error);
}
if ( request.hasContentType() ) {
MimeType rtype = request.getContentType() ;
MimeType type = getContentType() ;
if ( type == null ) {
setValue (ATTR_CONTENT_TYPE, rtype) ;
} else if ( rtype.match (type) < 0 ) {
Reply error = request.makeReply(HTTP.UNSUPPORTED_MEDIA_TYPE) ;
error.setContent ("<p>Invalid content type: "+type.toString());
throw new HTTPException (error) ;
}
}
try {
Client client = request.getClient();
if ( client != null && request.getExpect() != null ) {
client.sendContinue();
}
if ( fresource.newContent(request.getInputStream()) )
status = HTTP.CREATED;
else
status = HTTP.NO_CONTENT;
} catch (IOException ex) {
throw new ClientException(request.getClient(), ex);
}
if ( status == HTTP.CREATED ) {
reply = request.makeReply(status);
reply.setLocation(getURL(request));
reply.setContent ("<p>Entity body saved succesfully !") ;
} else {
reply = createDefaultReply(request, status);
}
return reply ;
}
@param request@exception ProtocolException@exception NotAProtocolException
public Reply options(Request request)
throws ProtocolException, NotAProtocolException
{
Reply reply = createDefaultReply(request, HTTP.OK);
reply.setContentLength(-1);
reply.setContentType(null);
if ( allowed != null )
reply.setHeaderValue(Reply.H_ALLOW, allowed);
return reply;
}
@param request@exception ProtocolException@exception NotAProtocolException
public Reply delete(Request request)
throws ProtocolException, NotAProtocolException
{
Reply error = request.makeReply(HTTP.NOT_IMPLEMENTED) ;
error.setContent("Method DELETE not implemented.") ;
throw new HTTPException (error) ;
}
@param request@exception ProtocolException@exception NotAProtocolException
public Reply link(Request request)
throws ProtocolException, NotAProtocolException
{
Reply error = request.makeReply(HTTP.NOT_IMPLEMENTED) ;
error.setContent("Method LINK not implemented.") ;
throw new HTTPException (error) ;
}
@param request@exception ProtocolException@exception NotAProtocolException
public Reply unlink(Request request)
throws ProtocolException, NotAProtocolException
{
Reply error = request.makeReply(HTTP.NOT_IMPLEMENTED) ;
error.setContent("Method UNLINK not implemented.") ;
throw new HTTPException (error) ;
}
@param request@exception HTTPException@exception ClientException
public Reply trace(Request request)
throws HTTPException, ClientException
{
Reply reply = createDefaultReply(request, HTTP.OK);
reply.setNoCache(); reply.setMaxAge(-1); reply.setContentMD5(null);
ByteArrayOutputStream ba = new ByteArrayOutputStream();
try {
reply.setContentType(new MimeType("message/http"));
request.dump(ba);
reply.setContentLength(ba.size());
} catch (Exception ex) {
ex.printStackTrace();
}
reply.setStream(new ByteArrayInputStream(ba.toByteArray()));
return reply;
}
@param request@exception ProtocolException@exception NotAProtocolException
public Reply extended(Request request)
throws ProtocolException, NotAProtocolException
{
String method = request.getMethod() ;
if ((method != null) && method.equals("BROWSE") && getBrowsableFlag())
return browse(request) ;
Reply error = request.makeReply(HTTP.NOT_IMPLEMENTED) ;
error.setContent("Method "+method+" not implemented.") ;
throw new HTTPException (error) ;
}
@param request
protected static MimeType browsetype = null;
protected synchronized MimeType getBrowseType() {
if ( browsetype == null ) {
try {
browsetype = new MimeType("application/x-navibrowse");
} catch (Exception ex) {
ex.printStackTrace();
}
}
return browsetype;
}
@param request@exception ProtocolException@return
public Reply browse (Request request)
throws ProtocolException
{
if (dresource == null) {
Reply error = request.makeReply(HTTP.NOT_IMPLEMENTED) ;
error.setContent("Method "+request.getMethod()+
" not implemented.") ;
throw new HTTPException (error) ;
}
Enumeration enum = dresource.enumerateResourceIdentifiers() ;
Vector resources = Sorter.sortStringEnumeration(enum) ;
int rsize = ((resources == null) ? 0 : resources.size()) ;
StringBuffer sb = new StringBuffer() ;
for (int i = 0 ; i < rsize ; i++) {
String rname = (String) resources.elementAt(i) ;
ResourceReference rr = null;
Resource r = null;
try {
rr = dresource.lookup(rname) ;
r = rr.lock();
if ( r instanceof DirectoryResource ) {
sb.append("application/x-navidir "+
rname+
"\r\n") ;
} else {
HTTPFrame itsframe =
(HTTPFrame) resource.getFrame(getClass());
if (itsframe != null) {
sb.append(itsframe.getContentType().toString()+
" "+
rname+
"\r\n") ;
}
}
} catch (InvalidResourceException ex) {
continue;
} finally {
rr.unlock();
}
}
Reply reply = request.makeReply(HTTP.OK) ;
reply.addPragma("no-cache");
reply.setNoCache();
reply.setContent(sb.toString()) ;
reply.setContentType(getBrowseType());
return reply ;
}
public synchronized ResourceFilter[] getFilters() {
ResourceFrame frames[] = collectFrames(filterClass);
if ( frames != null ) {
ResourceFilter f[] = new ResourceFilter[frames.length];
for (int i = 0 ; i < frames.length ; i++)
f[i] = (ResourceFilter) frames[i];
return f;
}
return null;
}
@param cls@return
public synchronized ResourceFilter[] getFilters(Class cls) {
ResourceFrame frames[] = collectFrames(cls);
if ( frames != null ) {
ResourceFilter f[] = new ResourceFilter[frames.length];
for (int i = 0 ; i < frames.length ; i++)
f[i] = (ResourceFilter) frames[i];
return f;
}
return null;
}
}