// // Copyright 2000 Perforce Software. All rights reserved. // // This file is part of Perforce - the FAST SCM System. // // p4wMimeContentPane: renders print data using mime type for content type #include <p4wp4.h> #include "p4wStrBuf.h" #include "p4wHtml.h" #include "p4wI18n.h" #include "p4wPane.h" #include "p4wMimeContentPane.h" #include "../Images/p4wIcons.h" #define NBRPREFIX "_" p4wMimeContentPane::p4wMimeContentPane( p4wView & ParentView, p4wRequest & Request ) : p4wPane( ParentView, Request ), fSeenData(0), fRenderedHdr(0), fOpenFailed(0) { } p4wMimeContentPane::~p4wMimeContentPane() { } void p4wMimeContentPane::RenderText( char *data ) { // // Output text data (via p4 print). Generate http content type // for this page only if we can resolve the content type // by examining the file syntax. if( !fSeenData ) { if (fRequest.GetCmd() == AC_P4CMDXML) RenderXMLHeader(); else RenderHeaderIfMapped( 0 ); ++fSeenData; } if (fRequest.GetCmd() == AC_P4CMDXML) { fXml.Clear(); fXml.XMLOutputText(data); fRequest << fXml; } else fRequest << data; } void p4wMimeContentPane::RenderBinary(char *data, int len) { // // Output binary data (via p4 print). Generate http // content type for this page only if we can resolve the // content type by examining the file suffix. if( !fSeenData ) { RenderHeaderIfMapped( 0 ); ++fSeenData; } fRequest.Write( data, len ); } void p4wMimeContentPane::RenderInfo(char *data, char level) { if( !fSeenData ) { ++fSeenData; if (fRequest.GetCmd() == AC_P4CMD || fRequest.GetCmd() == AC_P4CMDTAGGED) { fRequest << "HTTP/1.0 200 OK" << crlf; fRequest << "Content-Type: text/plain" << crlf; fRequest << crlf; } else if (fRequest.GetCmd() == AC_P4CMDXML) RenderXMLHeader(); } if (fRequest.GetCmd() == AC_P4CMDXML) { fXml.Clear(); fXml.XMLOutputInfo(data, level); fRequest << fXml; return; } if (*data != '\n') { int i; for (i = level - '0'; i > 0; i-- ) fRequest << "... "; } fRequest << data << "\n"; if( fRequest.GetJavascriptMode() == 2 ) // MSIE needs <br> in addition to the \n if (fRequest.GetCmd() != AC_P4CMD && fRequest.GetCmd() != AC_P4CMDTAGGED) fRequest << "<br>"; } void p4wMimeContentPane::RenderLocal( char *fileName, int defaultIsPlainText ) { Error e; StrBuf buf; FileSysType t; if( !fSeenData ) { RenderHeaderIfMapped( 0, 1, defaultIsPlainText ); ++fSeenData; } FileSys *f = FileSys::Create( FST_BINARY ); f->Set( StrRef( fileName ) ); if (!fRequest.isLocalRequest() && (f->Stat() & FSF_SYMLINK) && !SEC_ALLOW_CR8CHG_SYMLINKS) { delete f; RenderText("A Symlink may not be viewed by a remote browser."); return; } f->Open( FOM_READ, &e ); if(!e.Test()) { f->ReadWhole( &buf, &e ); } else fOpenFailed = 1; if(!e.Test()) { f->Close( &e ); } delete f; if( buf.Length() < 1 ) return; fRequest.Write( buf.Text(), buf.Length() ); } void p4wMimeContentPane::RenderError( char *data, int escapeHTML ) { // // More hacking for favicon.ico // Error means no //depot/favicon.ico file // so just send them the local (internal) favicon.ico if (!strcmp(fRequest.GetFullURL().Text(), "/favicon.ico")) { if( fRequest.GetJavascriptMode() == 2 || fRequest.IsHTTPS()) { p4wHtml htm; htm.httpHeader( 200 ); // MSIE && https require header htm.contentType( "image/vnd.microsoft.icon", 0 ); // Opera requires no header htm.contentLength( sizeof(faviconIcon) ); // Mozilla* handles both fRequest << htm; } ++fSeenData; RenderBinary((char *)faviconIcon, sizeof(faviconIcon)); return; } // // Output error from the server. We may need to // generate http header if this is the first data to // the page. if( !fSeenData ) { if (fRequest.GetCmd() == AC_P4CMDXML) RenderXMLHeader(); else RenderHeaderIfMapped( 1 ); ++fSeenData; } if (fRequest.GetCmd() == AC_P4CMDXML) { fXml.Clear(); fXml.XMLOutputError(data); fRequest << fXml; } else if (fSeenData && !fRenderedHdr && (fRequest.GetCmd() == AC_P4CMD || fRequest.GetCmd() == AC_P4CMDTAGGED)) fRequest << crlf << data << crlf; else p4wPane::RenderError( data, escapeHTML ); } void p4wMimeContentPane::End() { if (fRequest.GetCmd() == AC_P4CMD || fRequest.GetCmd() == AC_P4CMDTAGGED || fRequest.GetCmd() == AC_P4CMDXML) { if( !fSeenData ) RenderError( "P4 command returned no data, or there was an error.", 1 ); if (fRequest.GetCmd() == AC_P4CMDXML) { fXml.Clear(); fXml.XMLEnd(); fRequest << fXml; } return; } // // Print an error message if file is empty if( !fSeenData ) RenderError( "File not found, or file is empty.", 1 ); } void p4wMimeContentPane::RenderHeaderIfMapped( int errorOnly, int localCs, int defaultIsPlainText ) { // // If this is a "Download File from Workspace" request, // generate a Content-disposition header and return if (fRequest.GetCmd() == AC_DOWNLOADTOLOCAL) { RenderContentDispositionHeader(); return; } // // Generate header with content type if the file suffix // has a mapping in our mime table. However, if we are // generating an error as the first data to the page, we should // ignore the mapping and generate type of text/html. StrBuf contentType; p4wHtml htm; const char *charset = NULL; CharSetCvt::CharSet cs; // // If at all possible, refrain from setting a character set // type and let the browser handle it. However, in unicode mode // we may need to set the charset. If the text comes from a // "p4 print" command we want to set the charset to unicode. // If the file was read locally using FileSys, we should try to // use the local character set encoding. if( localCs && fRequest.GetUnicode() ) { cs = CharSetCvt::Lookup( fRequest.GetClientApi().GetCharset().Text() ); switch( cs ) { case CharSetCvt::UTF_8: charset = "utf-8"; break; case CharSetCvt::UTF_16: charset = "UTF-16"; break; case CharSetCvt::SHIFTJIS: charset = "shift_jis"; break; case CharSetCvt::EUCJP: charset = "EUC-JP"; break; default: break; } } else if( fRequest.GetUnicode() ) { charset = "utf-8"; } char *suffix = p4wI18n::safeStrrchr( fRequest.GetURL().Text(), '.' ); if( errorOnly ) { contentType.Set( "text/html" ); } else if (!strcmp(fRequest.GetFullURL().Text(), "/favicon.ico")) { contentType.Set( "image/x-icon" ); } else if( !suffix || !GetContentType( suffix, contentType ) ) { htm.httpHeader( 200 ); if( !charset && !defaultIsPlainText ) htm << crlf; else htm.contentType( "text/plain", 1, charset ); fRequest << htm; return; } // // Generate the content type using the appropriate content type, // as found in map or as dictated by the errorOnly parameter. htm.httpHeader( 200 ); htm.contentType( contentType.Text(), 1, charset ); fRenderedHdr++; fRequest << htm; } void p4wMimeContentPane::RenderContentDispositionHeader() { p4wHtml htm; htm.httpHeader( 200 ); StrBuf contentType; if (fRequest.GetJavascriptMode() == 2) contentType << "application/octetstream"; else contentType << "application/octet-stream"; htm.contentType( contentType.Text() ); fRequest << htm; if (fRequest.GetJavascriptMode() == 2 && fRequest.GetBrowserVersion() < 7.0) // MSIE 6 { fRequest << "Content-Disposition: inline; filename=\""; fRequest << fRequest.GetURL().Text() << "\"" << crlf; fRequest << "Content-Transfer-Encoding: binary" << crlf; fRequest << "Expires: 0" << crlf; fRequest << "Cache-Control: must-revalidate, post-check=0, pre-check=0" << crlf; fRequest << "Pragma: public" << crlf; } else { fRequest << "Content-Disposition: attachment; filename=\""; fRequest << fRequest.GetURL().Text() << "\"" << crlf; fRequest << "Content-Transfer-Encoding: binary" << crlf; fRequest << "Expires: 0" << crlf; fRequest << "Pragma: no-cache" << crlf; } fRequest << crlf; } int p4wMimeContentPane::GetContentType( char *suffix, StrBuf & contentType ) { // // Search the mime map for the suffix and set the // matching content type if found. If the suffix is // not in the map, return 0; otherwise 1. // // This mime mapping was derived from the Apache server // version 1.3. static struct contentTypes { char *suffix; char *type; } contentTypes[] = { { ".ai", "application/postscript" }, { ".aif", "audio/x-aiff" }, { ".aifc", "audio/x-aiff" }, { ".aiff", "audio/x-aiff" }, { ".asc", "text/plain" }, { ".au", "audio/basic" }, { ".avi", "video/x-msvideo" }, { ".bcpio", "application/x-bcpio" }, { ".bin", "application/octet-stream" }, { ".bmp", "image/bmp" }, { ".c", "text/plain" }, { ".cc", "text/plain" }, { ".cdf", "application/x-netcdf" }, // // This chm mapping is valid ONLY for IE! If not IE, // return no mime type for this suffix // { ".chm", "application/octet-stream" }, { ".class", "application/octet-stream" }, { ".cpio", "application/x-cpio" }, { ".cpp", "text/plain" }, { ".cpt", "application/mac-compactpro" }, { ".csh", "application/x-csh" }, { ".css", "text/css" }, { ".dcr", "application/x-director" }, { ".def", "text/plain" }, { ".dir", "application/x-director" }, { ".dll", "application/octet-stream" }, { ".dms", "application/octet-stream" }, { ".doc", "application/msword" }, { ".dot", "application/msword" }, { ".dvi", "application/x-dvi" }, { ".dxr", "application/x-director" }, { ".eps", "application/postscript" }, { ".etx", "text/x-setext" }, { ".exe", "application/octet-stream" }, { ".ez", "application/andrew-inset" }, { ".gif", "image/gif" }, { ".gtar", "application/x-gtar" }, { ".gz", "application/x-gzip" }, { ".h", "text/plain" }, { ".hdf", "application/x-hdf" }, { ".hqx", "application/mac-binhex40" }, { ".htm", "text/html" }, { ".html", "text/html" }, { ".ice", "x-conference/x-cooltalk" }, { ".ief", "image/ief" }, { ".iges", "model/iges" }, { ".igs", "model/iges" }, { ".jpe", "image/jpeg" }, { ".jpeg", "image/jpeg" }, { ".jpg", "image/jpeg" }, { ".js", "application/x-javascript" }, { ".kar", "audio/midi" }, { ".latex", "application/x-latex" }, { ".lha", "application/octet-stream" }, { ".lhz", "application/octet-stream" }, { ".m3u", "audio/x-mpegurl" }, { ".man", "application/x-troff-man" }, { ".me", "application/x-troff-me" }, { ".mesh", "model/mesh" }, { ".mid", "audio/midi" }, { ".midi", "audio/midi" }, { ".mif", "application/vnd.mif" }, { ".mov", "video/quicktime" }, { ".movie", "video/x-sgi-movie" }, { ".mp2", "audio/mpeg" }, { ".mp3", "audio/mpeg" }, { ".mpe", "video/mpeg" }, { ".mpeg", "video/mpeg" }, { ".mpg", "video/mpeg" }, { ".mpga", "audio/mpeg" }, { ".mpp", "application/vnd.ms-project" }, { ".ms", "application/x-troff-ms" }, { ".msh", "model/mesh" }, { ".msi", "application/x-msi" }, { ".mxu", "video/vnd.mpegurl" }, { ".nc", "application/x-netcdf" }, { ".oda", "application/oda" }, { ".pbm", "image/x-portable-bitmap" }, { ".pdb", "chemical/x-pdb" }, { ".pdf", "application/pdf" }, { ".pgm", "image/x-portable-graymap" }, { ".pgn", "application/x-chess-pgn" }, { ".pl", "text/plain" }, { ".png", "image/png" }, { ".pnm", "image/x-portable-anymap" }, { ".ppm", "image/x-portable-pixmap" }, { ".ppt", "application/vnd.ms-powerpoint" }, { ".ps", "application/postscript" }, { ".py", "text/plain" }, { ".qt", "video/quicktime" }, { ".ra", "audio/x-realaudio" }, { ".ram", "audio/x-pn-realaudio" }, { ".ras", "image/x-cmu-raster" }, { ".rc", "text/plain" }, { ".rgb", "image/x-rgb" }, { ".rm", "audio/x-pn-realaudio" }, { ".roff", "application/x-troff" }, { ".rpm", "audio/x-pn-realaudio-plugin" }, { ".rtf", "text/rtf" }, { ".rtx", "text/richtext" }, { ".sgm", "text/sgml" }, { ".sgml", "text/sgml" }, { ".sh", "application/x-sh" }, { ".shar", "application/x-shar" }, { ".silo", "model/mesh" }, { ".sit", "application/x-stuffit" }, { ".skd", "application/x-koan" }, { ".skm", "application/x-koan" }, { ".skp", "application/x-koan" }, { ".skt", "application/x-koan" }, { ".smi", "application/smil" }, { ".smil", "application/smil" }, { ".snd", "audio/basic" }, { ".so", "application/octet-stream" }, { ".spl", "application/x-futuresplash" }, { ".src", "application/x-wais-source" }, { ".sv4cpio", "application/x-sv4cpio" }, { ".sv4crc", "application/x-sv4crc" }, { ".swf", "application/x-shockwave-flash" }, { ".t", "application/x-troff" }, { ".tar", "application/x-tar" }, { ".tcl", "application/x-tcl" }, { ".tex", "application/x-tex" }, { ".texi", "application/x-textinfo" }, { ".texinfo", "application/x-texinfo" }, { ".tif", "image/tiff" }, { ".tiff", "image/tiff" }, { ".tr", "application/x-troff" }, { ".tsv", "text/tab-separated-values" }, { ".txt", "text/plain" }, { ".ustar", "application/x-ustar" }, { ".vcd", "application/x-cdlink" }, { ".vrml", "model/vrml" }, { ".vsd", "application/vnd.visio" }, { ".vss", "application/vnd.visio" }, { ".vst", "application/vnd.visio" }, { ".vsw", "application/vnd.visio" }, { ".wav", "audio/x-wav" }, { ".wbmp", "image/vnd.wap.wbmp" }, { ".wbxml", "application/vnd.wap.wbxml" }, { ".wml", "text/vnd.wap.wml" }, { ".wmlc", "application/vnd.wap.wmlc" }, { ".wmls", "text/vnd.wap.wmlscript" }, { ".wmlsc", "application/vnd.wap.wmlscriptc" }, { ".wmv", "video/wmv" }, { ".wrl", "model/vrml" }, { ".xbm", "image/x-xbitmap" }, { ".xls", "application/vnd.ms-excel" }, { ".xml", "text/xml" }, { ".xpm", "image/x-xpixmap" }, { ".xsl", "text/xml" }, { ".xwd", "image/x-windowdump" }, { ".xyz", "chemical/x-xyz" }, { ".zip", "application/zip" }, // New Office 2007 Document Types // { ".docm", "application/vnd.ms-word.document" }, { ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }, { ".dotm", "application/vnd.ms-word.template" }, { ".dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template" }, { ".potm", "application/vnd.ms-powerpoint.template" }, { ".potx", "application/vnd.openxmlformats-officedocument.presentationml.template" }, { ".ppam", "application/vnd.ms-powerpoint.addin" }, { ".ppsm", "application/vnd.ms-powerpoint.slideshow" }, { ".ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow" }, { ".pptm", "application/vnd.ms-powerpoint.presentation" }, { ".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation" }, { ".xlam", "application/vnd.ms-excel.addin" }, { ".xlsb", "application/vnd.ms-excel.sheet.binary" }, { ".xlsm", "application/vnd.ms-excel.sheet" }, { ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }, { ".xltm", "application/vnd.ms-excel.template" }, { ".xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template" }, }; if( !suffix ) return 0; StrPtr *s; StrBuf MIMEfile; Options *opts = fRequest.GetOpts(); if( s = (*opts)[ 'm' ] ) { MIMEfile.Set(s); } else { Enviro enviro; const char *mf; if( mf = enviro.Get( "P4WEBMIMEFILE" ) ) MIMEfile.Set(mf); } if (MIMEfile.Length() && GetCustomContentType( suffix, contentType, MIMEfile.Text() ) ) return 1; int mapSize = sizeof( contentTypes ) / sizeof( *contentTypes ); // // The .chm suffix mime mapping is only valid for IE. So if // the suffix is .chm and this is NOT IE, return nothing. if( !fRequest.GetUserAgent().Contains( StrRef("MSIE") ) && !StrPtr::CCompare( suffix, ".chm" ) ) return 0; for( int i = 0; i < mapSize; i++ ) if( !StrPtr::CCompare( suffix, contentTypes[i].suffix ) ) { contentType << contentTypes[i].type; return 1; } return 0; } int p4wMimeContentPane::GetCustomContentType( char *suffix, StrBuf & contentType, const char *filename ) { Error e; StrBuf buf; FileSys *f; int lgth = strlen(suffix); f = FileSys::Create( FST_TEXT ); f->Set( filename ); f->Open( FOM_READ, &e ); if(!e.Test()) { while(f->ReadLine( &buf, &e ) && !e.Test()) { #ifdef OS_NT if (!strnicmp(buf.Text(), suffix, lgth) && (*(buf.Text() + lgth) == '\t')) #else if (!strncmp(buf.Text(), suffix, lgth) && (*(buf.Text() + lgth) == '\t')) #endif { char *p = buf.Text() + lgth; while (*++p == '\t') ; contentType << p; p = contentType.Text() + contentType.Length(); while (*--p <= ' ' && p >= contentType.Text()) *p = '\0'; contentType.SetLength(); f->Close( &e ); delete f; return 1; } } f->Close( &e ); } else printf("Error trying to open %s\n", filename); delete f; return 0; } void p4wMimeContentPane::Render( StrDict * varList ) { if (fRequest.GetCmd() != AC_P4CMD && fRequest.GetCmd() != AC_P4CMDTAGGED && fRequest.GetCmd() != AC_P4CMDXML) return; if( !fSeenData ) { ++fSeenData; if (fRequest.GetCmd() == AC_P4CMDXML) { RenderXMLHeader(); } else { fRequest << "HTTP/1.0 200 OK" << crlf; fRequest << "Content-Type: text/plain" << crlf; fRequest << crlf; ++fRenderedHdr; } } if (fRequest.GetCmd() == AC_P4CMDXML) { fXml.Clear(); fXml.XMLOutputStat( varList ); fRequest << fXml; return; } int i; StrBuf msg; StrRef var, val; // Dump out the variables, using the GetVar( x ) interface. // Don't display the function (duh), which is only relevant to rpc. for( i = 0; varList->GetVar( i, var, val ); i++ ) { if( var == "func" ) continue; fRequest << "... " << var << " " << val << "\n"; if( fRequest.GetJavascriptMode() == 2 ) // MSIE needs <br> in addition to the \n fRequest << "<br>"; } fRequest << "\n"; if( fRequest.GetJavascriptMode() == 2 ) // MSIE needs <br> in addition to the \n fRequest << "<br>"; } void p4wMimeContentPane::RenderXMLHeader() { fRequest << "HTTP/1.0 200 OK" << crlf; fRequest << "Content-Type: text/xml" << crlf; fRequest << crlf; fXml.Clear(); fXml.XMLHeader(&fP4Cmd, &fP4CmdArgs, &fRequest.GetPort(), &fRequest.GetUser(), &fRequest.GetClient(), fRequest.GetUnicode()); fRequest << fXml; } void p4wMimeContentPane::AddP4CmdArg(char *p4arg) { if (fP4CmdArgs.Length()) fP4CmdArgs << " "; fP4CmdArgs << p4arg; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 12234 | Matt Attaway |
Rejigger P4Web project in preparation for official sunsetting The bin directory contains the last official builds of P4Web from the Perforce download site. P4Web is soon to be completely sunsetted; these builds are here for folks who don't want to build their own. To better handle the archived builds the source code has been moved into a separate src directory. |
||
//guest/perforce_software/p4web/Panes/p4wMimeContentPane.cpp | |||||
#1 | 8914 | Matt Attaway | Initial add of the P4Web source code |