Task 040: .ASHX File Format
Task 040: .ASHX File Format
File Format Specifications for .ASHX
The .ASHX file format is associated with ASP.NET Web Handler files, developed by Microsoft as part of the ASP.NET framework. It is not a binary or structured data format in the traditional sense, such as those with fixed headers or fields (e.g., PDF or JPEG). Instead, it is a plain text file containing source code that implements an HTTP handler. The file is dynamically compiled and executed by the ASP.NET runtime to process incoming HTTP requests and generate responses, which may include text, images, XML, or other content. The MIME type is determined at runtime by the handler logic (e.g., text/plain, image/png) and is not fixed to the file extension.
Key specifications include:
- File Structure: Begins with a directive (e.g.,
<%@ WebHandler Language="C#" Class="Handler" %>), followed by namespace imports, a class implementing theIHttpHandlerinterface, aProcessRequestmethod to handle requests, and anIsReusableproperty. - Encoding: Typically UTF-8 or ASCII, as it is human-readable source code.
- Usage: Designed for lightweight, performance-oriented web request handling, often for serving dynamic content without the overhead of full ASP.NET pages (.aspx).
- Compilation: Handlers are compiled on-the-fly by the server; no pre-compilation is required unless integrated into a larger project.
- Dependencies: Relies on the .NET Framework or .NET Core runtime, with references to assemblies like System.Web.
1. List of Properties Intrinsic to the .ASHX File Format
Given that .ASHX is a text-based format without binary structures, the intrinsic properties refer to parseable elements within the file content that define its functionality in the file system and runtime environment. These are derived from the standard structure of ASP.NET handlers and include:
- File Extension: .ashx (case-insensitive, but typically lowercase).
- MIME Type: Dynamic (set in code, e.g., via
context.Response.ContentType), defaults to text/plain if not specified. - Directive Line: The opening
<%@ WebHandler ... %>declaration, including attributes like Language and Class. - Language: The programming language used (e.g., C#, VB.NET).
- Class Name: The name of the handler class (must match the directive).
- Imported Namespaces: A list of
usingstatements (e.g., System, System.Web). - ProcessRequest Method: The core method body that processes HTTP requests and generates responses.
- IsReusable Property: A boolean indicating if the handler instance can be reused (typically false for stateful handlers).
- Content Encoding: The text encoding of the file (e.g., UTF-8).
- File Size: The size in bytes (variable, as it is text-based).
- Creation/Modification Dates: Standard file system timestamps (not format-specific but intrinsic to any file).
These properties can be extracted by parsing the text content, as there are no binary offsets or headers.
2. Two Direct Download Links for .ASHX Files
The following are direct links to sample .ASHX files hosted on GitHub (raw content for download):
- https://raw.githubusercontent.com/facebookarchive/real-time/master/samples/asp.net/callback.ashx
- https://raw.githubusercontent.com/Code-Inside/Samples/master/2008/Pdf/PdfHandler.ashx
These files contain typical ASP.NET handler code and can be downloaded directly via a web browser or tools like wget.
3. Ghost Blog Embedded HTML JavaScript for Drag-and-Drop .ASHX File Analysis
The following is a self-contained HTML snippet with embedded JavaScript that can be embedded in a Ghost blog post (or any HTML-enabled platform). It allows users to drag and drop a .ASHX file, parses the text content to extract the properties listed above, and displays them on the screen. It uses the FileReader API for client-side processing.
4. Python Class for Handling .ASHX Files
The following Python class opens a .ASHX file, reads and parses its content to extract properties, prints them to the console, and includes methods to write a new .ASHX file based on provided property values.
import re
import os
from datetime import datetime
class AshxHandler:
def __init__(self, filepath):
self.filepath = filepath
self.content = None
self.properties = {}
def read_and_decode(self):
with open(self.filepath, 'r', encoding='utf-8') as f:
self.content = f.read()
self._parse_properties()
return self.properties
def _parse_properties(self):
directive_match = re.search(r'<%@\s*WebHandler\s*Language="([^"]+)"\s*Class="([^"]+)"\s*%>', self.content, re.IGNORECASE)
namespaces = re.findall(r'using\s+([^;]+);', self.content)
process_request_match = re.search(r'public\s+void\s+ProcessRequest\s*\(HttpContext\s+context\)\s*\{([\s\S]*?)\}', self.content, re.IGNORECASE | re.DOTALL)
is_reusable_match = re.search(r'public\s+bool\s+IsReusable\s*\{\s*get\s*\{\s*return\s+(true|false);\s*\}\s*\}', self.content, re.IGNORECASE)
stat = os.stat(self.filepath)
self.properties = {
'File Extension': '.ashx',
'MIME Type': 'Dynamic (e.g., text/plain)',
'Directive Line': directive_match.group(0) if directive_match else 'Not found',
'Language': directive_match.group(1) if directive_match else 'Not found',
'Class Name': directive_match.group(2) if directive_match else 'Not found',
'Imported Namespaces': namespaces,
'ProcessRequest Method': process_request_match.group(1).strip() if process_request_match else 'Not found',
'IsReusable Property': is_reusable_match.group(1) if is_reusable_match else 'Not found',
'Content Encoding': 'UTF-8',
'File Size': f'{stat.st_size} bytes',
'Creation/Modification Dates': f'Created: {datetime.fromtimestamp(stat.st_ctime)}, Modified: {datetime.fromtimestamp(stat.st_mtime)}'
}
def print_properties(self):
for key, value in self.properties.items():
print(f'{key}: {value}')
def write_new_file(self, new_filepath, language='C#', class_name='Handler', namespaces=['System', 'System.Web'], process_request='// Add logic here', is_reusable=False):
content = f'<%@ WebHandler Language="{language}" Class="{class_name}" %>\n'
for ns in namespaces:
content += f'using {ns};\n'
content += f'public class {class_name} : IHttpHandler {{\n'
content += f' public void ProcessRequest(HttpContext context) {{\n{process_request}\n }}\n'
content += f' public bool IsReusable {{ get {{ return {str(is_reusable).lower()}; }} }}\n}}\n'
with open(new_filepath, 'w', encoding='utf-8') as f:
f.write(content)
# Example usage:
# handler = AshxHandler('example.ashx')
# handler.read_and_decode()
# handler.print_properties()
# handler.write_new_file('new.ashx')
5. Java Class for Handling .ASHX Files
The following Java class opens a .ASHX file, reads and parses its content to extract properties, prints them to the console, and includes methods to write a new .ASHX file.
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AshxHandler {
private String filepath;
private String content;
private final java.util.Map<String, Object> properties = new java.util.HashMap<>();
public AshxHandler(String filepath) {
this.filepath = filepath;
}
public java.util.Map<String, Object> readAndDecode() throws IOException {
content = new String(Files.readAllBytes(new File(filepath).toPath()), StandardCharsets.UTF_8);
parseProperties();
return properties;
}
private void parseProperties() throws IOException {
Pattern directivePattern = Pattern.compile("<%@\\s*WebHandler\\s*Language=\"([^\"]+)\"\\s*Class=\"([^\"]+)\"\\s*%>", Pattern.CASE_INSENSITIVE);
Matcher directiveMatcher = directivePattern.matcher(content);
String directive = directiveMatcher.find() ? directiveMatcher.group(0) : "Not found";
String language = directiveMatcher.find() ? directiveMatcher.group(1) : "Not found"; // Reset matcher if needed
directiveMatcher = directivePattern.matcher(content); // Re-match for class
String className = directiveMatcher.find() ? directiveMatcher.group(2) : "Not found";
Pattern namespacePattern = Pattern.compile("using\\s+([^;]+);");
Matcher namespaceMatcher = namespacePattern.matcher(content);
List<String> namespaces = new ArrayList<>();
while (namespaceMatcher.find()) {
namespaces.add(namespaceMatcher.group(1));
}
Pattern processRequestPattern = Pattern.compile("public\\s+void\\s+ProcessRequest\\s*\\(HttpContext\\s+context\\)\\s*\\{([\\s\\S]*?)\\}", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
Matcher processRequestMatcher = processRequestPattern.matcher(content);
String processRequest = processRequestMatcher.find() ? processRequestMatcher.group(1).trim() : "Not found";
Pattern isReusablePattern = Pattern.compile("public\\s+bool\\s+IsReusable\\s*\\{\\s*get\\s*\\{\\s*return\\s+(true|false);\\s*\\}\\s*\\}", Pattern.CASE_INSENSITIVE);
Matcher isReusableMatcher = isReusablePattern.matcher(content);
String isReusable = isReusableMatcher.find() ? isReusableMatcher.group(1) : "Not found";
File file = new File(filepath);
BasicFileAttributes attrs = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
FileTime creationTime = attrs.creationTime();
FileTime modTime = attrs.lastModifiedTime();
properties.put("File Extension", ".ashx");
properties.put("MIME Type", "Dynamic (e.g., text/plain)");
properties.put("Directive Line", directive);
properties.put("Language", language);
properties.put("Class Name", className);
properties.put("Imported Namespaces", namespaces);
properties.put("ProcessRequest Method", processRequest);
properties.put("IsReusable Property", isReusable);
properties.put("Content Encoding", "UTF-8");
properties.put("File Size", file.length() + " bytes");
properties.put("Creation/Modification Dates", "Created: " + creationTime + ", Modified: " + modTime);
}
public void printProperties() {
properties.forEach((key, value) -> System.out.println(key + ": " + value));
}
public void writeNewFile(String newFilepath, String language, String className, List<String> namespaces, String processRequest, boolean isReusable) throws IOException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(newFilepath))) {
writer.write("<%@ WebHandler Language=\"" + language + "\" Class=\"" + className + "\" %>\n");
for (String ns : namespaces) {
writer.write("using " + ns + ";\n");
}
writer.write("public class " + className + " : IHttpHandler {\n");
writer.write(" public void ProcessRequest(HttpContext context) {\n" + processRequest + "\n }\n");
writer.write(" public bool IsReusable { get { return " + isReusable + "; } }\n");
writer.write("}\n");
}
}
// Example usage:
// public static void main(String[] args) throws IOException {
// AshxHandler handler = new AshxHandler("example.ashx");
// handler.readAndDecode();
// handler.printProperties();
// List<String> ns = List.of("System", "System.Web");
// handler.writeNewFile("new.ashx", "C#", "Handler", ns, "// Add logic", false);
// }
}
6. JavaScript Class for Handling .ASHX Files
The following JavaScript class (Node.js compatible) opens a .ASHX file using the 'fs' module, reads and parses its content to extract properties, prints them to the console, and includes methods to write a new .ASHX file. It requires Node.js to run.
const fs = require('fs');
const path = require('path');
class AshxHandler {
constructor(filepath) {
this.filepath = filepath;
this.content = null;
this.properties = {};
}
readAndDecode() {
this.content = fs.readFileSync(this.filepath, 'utf-8');
this._parseProperties();
return this.properties;
}
_parseProperties() {
const directiveMatch = this.content.match(/<%@\s*WebHandler\s*Language="([^"]+)"\s*Class="([^"]+)"\s*%>/i);
const namespaces = this.content.match(/using\s+([^;]+);/g) || [];
const processRequestMatch = this.content.match(/public\s+void\s+ProcessRequest\s*\(HttpContext\s+context\)\s*\{([\s\S]*?)\}/i);
const isReusableMatch = this.content.match(/public\s+bool\s+IsReusable\s*\{\s*get\s*\{\s*return\s+(true|false);\s*\}\s*\}/i);
const stats = fs.statSync(this.filepath);
this.properties = {
'File Extension': '.ashx',
'MIME Type': 'Dynamic (e.g., text/plain)',
'Directive Line': directiveMatch ? directiveMatch[0] : 'Not found',
'Language': directiveMatch ? directiveMatch[1] : 'Not found',
'Class Name': directiveMatch ? directiveMatch[2] : 'Not found',
'Imported Namespaces': namespaces.map(ns => ns.replace(/using\s+|\s*;/g, '')),
'ProcessRequest Method': processRequestMatch ? processRequestMatch[1].trim() : 'Not found',
'IsReusable Property': isReusableMatch ? isReusableMatch[1] : 'Not found',
'Content Encoding': 'UTF-8',
'File Size': `${stats.size} bytes`,
'Creation/Modification Dates': `Created: ${new Date(stats.birthtime)}, Modified: ${new Date(stats.mtime)}`
};
}
printProperties() {
Object.entries(this.properties).forEach(([key, value]) => {
console.log(`${key}: ${value}`);
});
}
writeNewFile(newFilepath, language = 'C#', className = 'Handler', namespaces = ['System', 'System.Web'], processRequest = '// Add logic here', isReusable = false) {
let content = `<%@ WebHandler Language="${language}" Class="${className}" %>\n`;
namespaces.forEach(ns => {
content += `using ${ns};\n`;
});
content += `public class ${className} : IHttpHandler {\n`;
content += ` public void ProcessRequest(HttpContext context) {\n${processRequest}\n }\n`;
content += ` public bool IsReusable { get { return ${isReusable}; } }\n`;
content += `}\n`;
fs.writeFileSync(newFilepath, content, 'utf-8');
}
}
// Example usage:
// const handler = new AshxHandler('example.ashx');
// handler.readAndDecode();
// handler.printProperties();
// handler.writeNewFile('new.ashx');
7. C++ Class for Handling .ASHX Files
The following C++ class opens a .ASHX file, reads and parses its content to extract properties, prints them to the console, and includes methods to write a new .ASHX file. It uses standard libraries for file I/O and regex parsing. Compile with C++11 or later.
#include <iostream>
#include <fstream>
#include <string>
#include <regex>
#include <vector>
#include <map>
#include <sys/stat.h>
#include <ctime>
class AshxHandler {
private:
std::string filepath;
std::string content;
std::map<std::string, std::string> properties; // Using string for simplicity; lists as comma-separated
public:
AshxHandler(const std::string& fp) : filepath(fp) {}
std::map<std::string, std::string> readAndDecode() {
std::ifstream file(filepath);
if (file) {
content.assign((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
parseProperties();
}
return properties;
}
void parseProperties() {
std::regex directiveRegex(R"(<%@\s*WebHandler\s*Language="([^"]+)"\s*Class="([^"]+)"\s*%>)", std::regex::icase);
std::smatch directiveMatch;
std::string directive = std::regex_search(content, directiveMatch, directiveRegex) ? directiveMatch[0] : "Not found";
std::string language = directiveMatch.size() > 1 ? directiveMatch[1] : "Not found";
std::string className = directiveMatch.size() > 2 ? directiveMatch[2] : "Not found";
std::regex namespaceRegex(R"(using\s+([^;]+);)");
std::sregex_iterator nsIter(content.begin(), content.end(), namespaceRegex);
std::vector<std::string> namespaces;
for (std::sregex_iterator end; nsIter != end; ++nsIter) {
namespaces.push_back((*nsIter)[1]);
}
std::string nsList;
for (const auto& ns : namespaces) {
if (!nsList.empty()) nsList += ", ";
nsList += ns;
}
std::regex processRequestRegex(R"(public\s+void\s+ProcessRequest\s*\(HttpContext\s+context\)\s*\{([\s\S]*?)\})", std::regex::icase);
std::smatch processRequestMatch;
std::string processRequest = std::regex_search(content, processRequestMatch, processRequestRegex) ? processRequestMatch[1] : "Not found";
std::regex isReusableRegex(R"(public\s+bool\s+IsReusable\s*\{\s*get\s*\{\s*return\s+(true|false);\s*\}\s*\})", std::regex::icase);
std::smatch isReusableMatch;
std::string isReusable = std::regex_search(content, isReusableMatch, isReusableRegex) ? isReusableMatch[1] : "Not found";
struct stat statbuf;
stat(filepath.c_str(), &statbuf);
char ctimeBuf[64], mtimeBuf[64];
std::strftime(ctimeBuf, sizeof(ctimeBuf), "%Y-%m-%d %H:%M:%S", std::localtime(&statbuf.st_ctime));
std::strftime(mtimeBuf, sizeof(mtimeBuf), "%Y-%m-%d %H:%M:%S", std::localtime(&statbuf.st_mtime));
properties["File Extension"] = ".ashx";
properties["MIME Type"] = "Dynamic (e.g., text/plain)";
properties["Directive Line"] = directive;
properties["Language"] = language;
properties["Class Name"] = className;
properties["Imported Namespaces"] = nsList;
properties["ProcessRequest Method"] = processRequest;
properties["IsReusable Property"] = isReusable;
properties["Content Encoding"] = "UTF-8";
properties["File Size"] = std::to_string(statbuf.st_size) + " bytes";
properties["Creation/Modification Dates"] = std::string("Created: ") + ctimeBuf + ", Modified: " + mtimeBuf;
}
void printProperties() {
for (const auto& pair : properties) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
}
void writeNewFile(const std::string& newFilepath, const std::string& language = "C#", const std::string& className = "Handler",
const std::vector<std::string>& namespaces = {"System", "System.Web"}, const std::string& processRequest = "// Add logic here",
bool isReusable = false) {
std::ofstream out(newFilepath);
if (out) {
out << "<%@ WebHandler Language=\"" << language << "\" Class=\"" << className << "\" %>\n";
for (const auto& ns : namespaces) {
out << "using " << ns << ";\n";
}
out << "public class " << className << " : IHttpHandler {\n";
out << " public void ProcessRequest(HttpContext context) {\n" << processRequest << "\n }\n";
out << " public bool IsReusable { get { return " << (isReusable ? "true" : "false") << "; } }\n";
out << "}\n";
}
}
};
// Example usage:
// int main() {
// AshxHandler handler("example.ashx");
// handler.readAndDecode();
// handler.printProperties();
// std::vector<std::string> ns = {"System", "System.Web"};
// handler.writeNewFile("new.ashx");
// return 0;
// }