diff --git a/build.gradle b/build.gradle index 5036696ec..90f892810 100644 --- a/build.gradle +++ b/build.gradle @@ -328,6 +328,7 @@ sourceSets { include '**/*.pm' include '**/*.pl' include '**/*.pod' + include '**/media.types' include 'lib/ExtUtils/xsubpp' include 'bin/**' include 'META-INF/services/**' @@ -345,6 +346,7 @@ tasks.named('processResources', Copy) { from(sourceSets.main.resources.srcDirs) { include '**/*.pm' include '**/*.pod' + include '**/media.types' include 'bin/**' include 'META-INF/services/**' } diff --git a/dev/design/io_handle_lifecycle.md b/dev/design/io_handle_lifecycle.md new file mode 100644 index 000000000..0bfe92229 --- /dev/null +++ b/dev/design/io_handle_lifecycle.md @@ -0,0 +1,180 @@ +# IO Handle Lifecycle & Fileno Registry + +## Overview + +This document explains how PerlOnJava manages the lifecycle of IO handles +(file descriptors), the fileno registry, and the tradeoffs made due to the +absence of Perl 5's reference counting and DESTROY mechanism. + +## Background: How Perl 5 Does It + +In Perl 5, IO handles are closed automatically when the **last reference** +to the containing glob is dropped. The interpreter uses reference counting +(`SvREFCNT`) to track this. When the refcount reaches zero, `sv_clear()` +calls `gp_free()` which closes the IO. The `DESTROY` method can also +participate in cleanup. + +PerlOnJava has **none of these mechanisms**: +- No reference counting +- No DESTROY (object destructors never run) +- JVM garbage collection is non-deterministic + +This creates a fundamental tension: we want to close file handles promptly +(to avoid fd leaks and flush data), but we can't safely determine when a +handle is truly unreferenced. + +## The Fileno Registry + +### Purpose + +PerlOnJava's "virtual fd" registry maps small sequential integers to +`RuntimeIO` objects. This is needed for: + +1. **dup-by-fd operations**: `open(*FH, ">&3")` — looks up fd 3 in the registry +2. **4-arg select()**: Uses fd numbers in bit-vectors +3. **fileno() return values**: Perl code expects `fileno($fh)` to return an integer + +### Design + +``` + stdin → fd 0 (native, via StandardIO) + stdout → fd 1 (native, via StandardIO) + stderr → fd 2 (native, via StandardIO) + files → fd 3, 4, 5, ... (from AtomicInteger counter, via registry) +``` + +- `filenoToIO`: fd → RuntimeIO (lookup by fd number) +- `ioToFileno`: RuntimeIO → fd (lookup by handle) +- `nextFileno`: AtomicInteger, starts at 3, only increments + +### Fd Numbers Are Never Recycled + +A recycling mechanism (using `ConcurrentLinkedQueue freedFilenos`) +was attempted and removed. The problem: + +1. `closeIOOnDrop()` closes a RuntimeIO and puts its fd into the free queue +2. The next `assignFileno()` picks up the recycled fd +3. But the closed RuntimeIO was still referenced by another variable +4. Now two RuntimeIO objects claim the same fd → registry corruption + +Without reference counting, we cannot know when a fd is truly free to reuse. +The monotonic counter wastes fd numbers but is safe. + +### Lazy vs Eager Fileno Assignment + +- **Eager** (dup'd handles): `duplicateFileHandle()` calls `assignFileno()` + immediately. Dup'd handles need a fd right away because Capture::Tiny + and similar code do `open(*STDOUT, ">&" . fileno($saved))`. + +- **Lazy** (regular files, pipes): `assignFileno()` is deferred until + `fileno()` is first called. Many handles (especially temp files in + Capture::Tiny) never have `fileno()` called on them, so this avoids + wasting fd numbers. + +## closeIOOnDrop: The Eager-Close Heuristic + +### What It Does + +When a `RuntimeScalar` holding a `GLOBREFERENCE` is being cleared, +`closeIOOnDrop()` checks if the glob's IO should be closed: + +1. If the glob is still in a stash (named, like `*main::MYFILE`) → skip +2. If the glob is anonymous (gensym'd, deleted from stash) → close the IO + +### Where It's Called + +| Call site | Safe? | Notes | +|-----------|-------|-------| +| `undefine()` | Yes | Explicit `undef $fh` — user is intentionally discarding | +| `setLarge(null)` | Yes | Variable set to undef/null | +| `setLarge(value)` | **REMOVED** | Variable reassignment — other refs may still exist | +| `set(int/long/...)` | Never called | Primitive setters don't check IO at all | + +### The Capture::Tiny Bug (Why setLarge Was Changed) + +Capture::Tiny's `_copy_std()` saves STDOUT/STDERR handles in a loop: + +```perl +sub _copy_std { + my %handles; + for my $h ( qw/stdout stderr/ ) { + my $redir = ">&"; + _open $handles{$h} = IO::Handle->new(), $redir . uc($h); + } + return \%handles; +} +``` + +After macro expansion, this is roughly: + +```perl +my $h; # gensym'd by IO::Handle->new() + +# Iteration 1: save STDOUT +$h = IO::Handle->new(); # $h → GLOB(GEN1) +open($h, ">&STDOUT"); # GEN1's IO = dup of STDOUT (fd 3) +$handles{stdout} = $h; # hash also → GLOB(GEN1) + +# Iteration 2: save STDERR +$h = IO::Handle->new(); # ← THIS TRIGGERS setLarge() on $h + # old value: GLOBREFERENCE to GEN1 + # closeIOOnDrop() closes GEN1's IO! + # $handles{stdout} is now BROKEN +open($h, ">&STDERR"); # GEN2's IO = dup of STDERR +$handles{stderr} = $h; +``` + +The failure chain: + +1. `$h = IO::Handle->new()` calls `$h.set(new_value)` +2. `setLarge()` sees old value is GLOBREFERENCE to GEN1 (gensym'd, not in stash) +3. `closeIOOnDrop()` closes GEN1's RuntimeIO → `ioHandle = ClosedIOHandle` +4. With fd recycling, fd 3 goes to the free queue → next dup gets fd 3 too! +5. `$handles{stdout}` still points to GEN1 → `fileno()` returns undef +6. Later `open(*STDOUT, ">&" . fileno($handles{stdout}))` → `">&"` → "Bad fd" + +### The Fix + +1. **Removed `closeIOOnDrop()` from `setLarge()` assignment path** — we + cannot safely determine if other variables reference the same glob. + +2. **Removed fd recycling** — without reference counting, recycled fds + can collide with still-referenced handles. + +### Tradeoffs + +| Aspect | Before | After | +|--------|--------|-------| +| Capture::Tiny | Broken (Bad fd on restore) | Works correctly | +| Explicit `close($fh)` | Works | Works (unchanged) | +| `undef $fh` | Closes IO | Closes IO (unchanged) | +| Reassigning `$fh = other` | Closes old IO (dangerous) | Old IO leaks until GC | +| Fd numbers | Recycled (unsafe) | Monotonic (safe, wastes numbers) | + +### Future Improvements + +If IO handle leaks become a practical problem, consider: + +1. **Reference counting on RuntimeGlob**: Track how many RuntimeScalars + point to each glob. Only close IO when count reaches zero. + - Pro: Correct, matches Perl 5 semantics + - Con: Adds overhead to every set() call involving GLOBREFERENCEs + +2. **Java Cleaner API**: Register a cleanup action with `java.lang.ref.Cleaner` + when a RuntimeGlob is created. When the glob becomes phantom-reachable, + the cleaner closes the IO. + - Pro: No overhead on set(); leverages JVM GC + - Con: Non-deterministic timing; data may not be flushed promptly + +3. **WeakReference-based fd tracking**: Use WeakReferences to track + RuntimeIO handles. Periodically scan for collected references and + reclaim their fds. + - Pro: Safe fd recycling + - Con: Adds a background task; still non-deterministic + +## Files Involved + +- `RuntimeScalar.java` — `setLarge()`, `undefine()`, `closeIOOnDrop()` +- `RuntimeIO.java` — fileno registry, `assignFileno()`, `unregisterFileno()`, `fileno()`, `close()` +- `IOOperator.java` — `duplicateFileHandle()`, `openFileHandleDup()` +- `RuntimeGlob.java` — `setIO()`, glob name and stash management diff --git a/dev/modules/www_mechanize.md b/dev/modules/www_mechanize.md new file mode 100644 index 000000000..ee6e56773 --- /dev/null +++ b/dev/modules/www_mechanize.md @@ -0,0 +1,484 @@ +# WWW::Mechanize Support for PerlOnJava + +## Status: Phase 11 Complete — 99.8% non-server pass rate + all local server tests pass + +**Branch**: `feature/www-mechanize-support` +**Date started**: 2026-04-04 + +## Background + +WWW::Mechanize is a widely-used CPAN module for programmatic web browsing and +form handling. It depends on LWP::UserAgent (already supported at 100%), plus +HTML::Form, HTML::TreeBuilder (HTML-Tree), and Tie::RefHash. Running +`./jcpan -t WWW::Mechanize` reveals several PerlOnJava bugs that block the +module from loading and passing its dependency tests. + +## Current State (before fixes) + +### Dependency Test Summary + +| Module | Test Results | Blocker | +|--------|-------------|---------| +| **WWW::Mechanize** | Most tests FAIL | `Bad name after Tie::RefHash::` prevents loading | +| **HTML::Form** | 10/12 test files FAIL, 6/13 subtests fail | `HTML::Form->parse()` returns undef (HTMLParser bug) | +| **HTML::Tree** | 17/23 test files FAIL, 169/910 subtests fail | `UNIVERSAL::isa(\&code, 'CODE')` returns false | +| **Capture::Tiny** | 109/331 subtests fail | `fork()` not supported on JVM | +| **Test::Memory::Cycle** | 7/7 test files FAIL | `Devel::Cycle` not installed | + +### Root Cause Analysis + +Six distinct PerlOnJava bugs were identified: + +#### Bug 1: Parser rejects NEWLINE after trailing `::` (CRITICAL) +- **File**: `IdentifierParser.java:581` +- **Symptom**: `Bad name after Tie::RefHash::::` when parsing `tie my %c, Tie::RefHash::\n or ...` +- **Root cause**: The validation gate after `::` doesn't allow NEWLINE or WHITESPACE tokens, but the top-of-loop check (line 543) already handles them correctly. The validation blocks the `continue` that would reach it. +- **Impact**: WWW::Mechanize cannot load at all. Every test fails. + +#### Bug 2: UNIVERSAL::isa() missing CODE reference type (CRITICAL) +- **File**: `Universal.java:240-256` +- **Symptom**: `UNIVERSAL::isa(\&sub, 'CODE')` returns false +- **Root cause**: The `isa` method's switch statement handles REFERENCE, ARRAYREFERENCE, HASHREFERENCE, GLOBREFERENCE, FORMAT, REGEX — but not CODE. CODE refs fall through to the default case which stringifies them and looks up as a class name. +- **Impact**: HTML::Element::traverse() never invokes callbacks, so `as_HTML()` and `as_XML()` return empty strings. All HTML::Tree rendering tests fail (75/75 in assubs.t, 10/11 in tag-rendering.t). This is a generic bug affecting any CPAN module using `UNIVERSAL::isa($ref, 'CODE')`. + +#### Bug 3: HTMLParser array-ref accumulator handlers missing (HIGH) +- **File**: `HTMLParser.java:fireEvent()` line ~466 +- **Symptom**: `HTML::Form->parse(...)` returns undef/empty list +- **Root cause**: `fireEvent()` handles STRING callbacks (method names) and CODE callbacks, but not ARRAYREFERENCE callbacks. HTML::PullParser/HTML::TokeParser registers an array ref as the event handler to accumulate parsed tokens. Since the array-ref branch is missing, parsed events are silently dropped and the accumulator stays empty. +- **Also needed**: Argspec parsing — the argspec string (e.g., `"'S',tagname,attr,attrseq,text"`) is fetched but completely ignored. Need to parse it and construct proper event data arrays. +- **Impact**: HTML::Form::parse() returns no forms. Most HTML::Form tests fail. + +#### Bug 4: Overload dispatch doesn't set $AUTOLOAD (MEDIUM) +- **File**: `OverloadContext.java:resolveOverloadMethodName()` line ~395 +- **Symptom**: `substr outside of string` at URI/WithBase.pm line 51; `Can't locate object method "" via package "URI::http"` +- **Root cause**: When overload dispatch resolves a string method name (e.g., `as_string` for `""` overload), and `findMethodInHierarchy` returns AUTOLOAD instead of the actual method, `tryOverload` calls AUTOLOAD without setting the `$AUTOLOAD` variable. Normal method dispatch properly sets `$AUTOLOAD` but overload dispatch does not. +- **Impact**: URI::WithBase stringification fails. Affects link.t, image-new.t, link-base.t in WWW::Mechanize tests. + +#### Bug 5: Devel::Cycle not available (LOW) +- **Symptom**: Test::Memory::Cycle fails because `use Devel::Cycle` fails +- **Root cause**: Devel::Cycle is not installed. Even if installed, it depends on `Scalar::Util::isweak()` which is a no-op in PerlOnJava (JVM handles cycles natively). +- **Impact**: Test::Memory::Cycle tests all fail. This is a build_requires dependency, not a runtime dependency. + +#### Bug 6: Capture::Tiny fork dependency (LOW, KNOWN) +- **Symptom**: Capture::Tiny tee functions fail; basic capture functions have issues +- **Root cause**: `fork()` returns undef on JVM. Already known limitation. +- **Impact**: Test::Output tests fail (build_requires for WWW::Mechanize). Not a runtime blocker. + +## Implementation Plan + +### Phase 1: Parser and UNIVERSAL::isa fixes (Quick wins) + +**Files to modify:** +1. `src/main/java/org/perlonjava/frontend/parser/IdentifierParser.java` — Add NEWLINE, WHITESPACE, and `,` to allowed tokens after `::` in the validation gate at line 581 +2. `src/main/java/org/perlonjava/runtime/perlmodule/Universal.java` — Add CODE case to the isa() switch statement and boolean check + +**Expected impact:** WWW::Mechanize can load. HTML::Tree rendering tests pass (~75+ subtests fixed). + +### Phase 2: HTMLParser array-ref accumulator + argspec parsing + +**Files to modify:** +1. `src/main/java/org/perlonjava/runtime/perlmodule/HTMLParser.java` + - Add ARRAYREFERENCE branch in `fireEvent()` + - Implement `buildEventDataFromArgspec()` method to parse argspec strings + - Handle argspec tokens: literal strings (`'S'`, `'E'`, `'T'`), `tagname`, `attr`, `attrseq`, `text`, `is_cdata`, `self`, `token0`, `offset`, `length`, `event`, `line`, `column`, `tag` + - For ARRAYREFERENCE callbacks: build event data array per argspec, push as array ref onto accumulator + - Also apply argspec for existing CODE and STRING callback types (currently ignored) + +**Expected impact:** HTML::Form::parse() returns forms. Most HTML::Form tests pass. + +### Phase 3: Overload AUTOLOAD dispatch fix + +**Files to modify:** +1. `src/main/java/org/perlonjava/runtime/runtimetypes/OverloadContext.java` + - In `resolveOverloadMethodName()`: after `findMethodInHierarchy` returns, check if the result has `autoloadVariableName` set. If so, set the `$AUTOLOAD` global variable before returning. + +**Expected impact:** URI::WithBase stringification works. link.t, image-new.t, link-base.t tests improve. + +### Phase 4: Devel::Cycle stub + +**Files to create:** +1. `src/main/perl/lib/Devel/Cycle.pm` — No-op stub (same pattern as Test::LeakTrace) + - Export `find_cycle` and `find_weakened_cycle` + - Both functions are no-ops (never call callback = no cycles found) + - On JVM, tracing GC handles cycles natively + +**Expected impact:** Test::Memory::Cycle loads and reports no cycles. + +### Phase 5: Verification and cleanup + +1. Run `make` — ensure no regressions in unit tests +2. Re-run `./jcpan -t WWW::Mechanize` — measure improvement +3. Update this document with final test counts + +## Test Commands + +```bash +# Full build + unit tests +make + +# Test WWW::Mechanize and all dependencies +./jcpan -t WWW::Mechanize + +# Quick smoke test for parser fix +./jperl -e 'tie my %c, Tie::RefHash:: or print "ok\n"' + +# Quick smoke test for UNIVERSAL::isa fix +./jperl -e 'print UNIVERSAL::isa(sub{}, "CODE") ? "ok" : "FAIL", "\n"' + +# Quick smoke test for HTMLParser fix +./jperl -e 'use HTML::TokeParser; my $p = HTML::TokeParser->new(\"test"); my $t = $p->get_tag("b"); print defined $t ? "ok" : "FAIL", "\n"' +``` + +## Progress Tracking + +### Current Status: Phase 11 complete — 542/545 non-server subtests (99.8%) + all 18 local server tests pass + +### Completed Phases +- [x] Phase 1: Parser and UNIVERSAL::isa fixes (2026-04-04) + - Fixed IdentifierParser.java: NEWLINE/WHITESPACE/comma after `::` + - Fixed Universal.java: Added CODE case to isa() +- [x] Phase 2: HTMLParser array-ref accumulator + argspec (2026-04-04) + - Added ARRAYREFERENCE handler branch in fireEvent() + - Implemented buildEventDataFromArgspec() for argspec token parsing + - Added argspec processing for STRING and CODE callback types +- [x] Phase 3: Overload AUTOLOAD dispatch fix (2026-04-04) + - Fixed OverloadContext.java to set $AUTOLOAD for overload dispatch +- [x] Phase 4: Devel::Cycle stub (2026-04-04) + - Created src/main/perl/lib/Devel/Cycle.pm no-op stub +- [x] Phase 5: Verification (2026-04-04) + - Fixed HTMLParser skipSelf bug for method callbacks + - `make` passes (all unit tests green) + - WWW::Mechanize non-local tests: 431/478 pass (90.2%) + - Local tests: 14/139 pass (need fork() for HTTP::Daemon) +- [x] Phase 6: Chunked parsing, strict subs, self-closing tags (2026-04-05) + - Fixed HTMLParser to buffer incomplete tags across parse() chunk boundaries + - Fixed strict subs to allow trailing `::` barewords (package name constants) + - Fixed self-closing `/>` to emit `'/' => '/'` attribute in non-XML mode + - `make` passes (all unit tests green) + - WWW::Mechanize non-local tests: 513/529 pass (97.0%) +- [x] Phase 7: Labeled blocks, script/style raw text, media.types (2026-04-05) + - Fixed EmitStatement.java: labeled blocks are valid targets for unlabeled last/next/redo + - Added HTMLParser raw text handling for script/style/xmp/listing/plaintext/textarea/title + - Bundled LWP/media.types data file for MIME type lookups + - `make` passes (all unit tests green) + - WWW::Mechanize non-local tests: 522/532 pass (98.1%) +- [x] Phase 8: Capture::Tiny fileno/dup chain fix (2026-04-05) + - Fixed fileno() to return valid fd numbers for all file/pipe handles + - Bridged findFileHandleByDescriptor() to RuntimeIO fileno registry + - Added guard for empty fd in dup mode (prevents STDOUT corruption) + - Added fileno unregistration on close() to prevent fd leaks + - Capture::Tiny capture/capture_stdout/capture_stderr/capture_merged: WORKING + - `make` passes (all unit tests green) + - WWW::Mechanize non-local tests: 529/532 pass (99.4%) + - dump.t: 1/7 -> 7/7, mech-dump/file_not_found.t: 0/1 -> 1/1 +- [x] Phase 9: HTTP::Daemon pure Perl verified (2026-04-05) + - HTTP::Daemon new/accept/get_request/send_response: all working (pure Perl, no changes needed) + - LocalServer piped-open pattern works with jperl + - WWW::Mechanize t/local/ tests: 17/19 pass (0 failures, 2 server-exit timeouts) +- [x] Phase 10: closeIOOnDrop for gensym'd socket globs (2026-04-05) + - Added `closeIOOnDrop()` to RuntimeScalar.java: closes IO on `undef()` and `set()` for GLOBREFERENCE + - Fixed RuntimeIO.java fallback to use `getExistingGlobalIO()` (non-auto-vivifying) instead of `getGlobalIO()` + - Added `getExistingGlobalIO()` to GlobalVariable.java + - Root cause: `getRuntimeIO()` fallback re-created stash entries that gensym had deleted, preventing socket close + - All 18 local server tests pass with no timeouts (including redirect tests) + - back.t: 47/47, get.t: 34/34 (both previously had server-exit timeouts) +- [x] Phase 11: CDATA marked_sections + media.types MIME fix (2026-04-05) + - Added SGML marked_sections support to HTMLParser: CDATA, IGNORE, INCLUDE + - Script raw content handler skips CDATA when looking for closing tag (marked_sections only) + - Added LWP/media.types to JAR resources (build.gradle + pom.xml) + - find_link_xhtml.t: 7/10 -> 10/10 (CDATA + legacy mode) + - image-parse.t: 41/47 -> 47/47 (CSS MIME type detection) + - `make` passes (all unit tests green) + +### Bug 7: HTMLParser argspec "self" doubled for method callbacks (FIXED) +- **File**: `HTMLParser.java:fireEvent()` + `buildEventDataFromArgspec()` +- **Symptom**: `Not an ARRAY reference` when HTML::TreeBuilder parses HTML +- **Root cause**: For STRING (method name) callbacks, "self" in argspec was both + pushed as the invocant AND included in the argspec args. The XS behavior is + to use "self" only as the invocant for method dispatch, not as an argument. + This doubled $self, shifting all other args by 1 position. +- **Fix**: Added `skipSelf` parameter to `buildEventDataFromArgspec()`. + STRING callbacks use skipSelf=true; CODE/ARRAY use skipSelf=false. + +### Bug 8: HTMLParser incomplete tag buffering across chunks (FIXED) +- **File**: `HTMLParser.java:parseHtml()` +- **Symptom**: Tags split at 512-byte chunk boundary get truncated (e.g., URL + `http://www.bbc.co.uk/` becomes `http://www.bbc`) +- **Root cause**: `parseHtml()` buffered incomplete comments/declarations/PIs but + NOT incomplete start or end tags. When `HTML::PullParser` feeds 512-byte chunks, + any tag straddling a boundary was parsed with truncated content. +- **Fix**: Added incomplete tag detection after attribute parsing. If `>` not found + before end of input, buffer from `tagStart` for next `parse()` call. Also handles + bare `<` at end of input and incomplete end tags. + +### Bug 9: Strict subs rejects trailing `::` barewords (FIXED) +- **Files**: `EmitLiteral.java:emitIdentifier()` + `BytecodeCompiler.java` +- **Symptom**: `Bareword "Tie::RefHash::" not allowed while "strict subs" in use` +- **Root cause**: The strict subs check had zero exemptions for any bareword pattern. + In Perl, barewords ending with `::` are package name constants, always allowed. +- **Fix**: Added early return for names ending with `::` that strips the trailing `::` and + emits as a string literal. Applied in both JVM and bytecode backends. + +### Bug 10: Self-closing `/>` emits synthetic end tag in non-XML mode (FIXED) +- **File**: `HTMLParser.java:parseHtml()` +- **Symptom**: `get_phrase()` stops early at synthetic `` end tag; `` + missing `'/' => '/'` attribute expected by tests +- **Root cause**: In non-XML mode, `/>` was treated as self-closing with a synthetic + end event. Perl's HTML::Parser treats `/` as a boolean attribute `'/' => '/'` and + does NOT emit an end event. Synthetic end tags only happen in `xml_mode`. +- **Fix**: In non-XML mode, add `'/'` to attrs/attrseq; only emit synthetic end tag + when `xml_mode` is true. + +### Phase 7: Remaining failures — RESOLVED (2026-04-05) + +**Non-local test results: 541/532+13 pass (99.8%)** + +| Test File | Result | Root Cause | Status | +|-----------|--------|------------|--------| +| dump.t | 7/7 | Fixed by Capture::Tiny fileno/dup fix | ✅ FIXED | +| field.t | 15/16 (TODO fail) | Expected: HTML::TokeParser limitation | OK (TODO test) | +| find_link_xhtml.t | 10/10 | SGML marked_sections / CDATA support added | ✅ FIXED (Phase 11) | +| image-parse.t | 47/47 | media.types added to JAR resources | ✅ FIXED (Phase 11) | +| mech-dump/file_not_found.t | 1/1 | Fixed by Capture::Tiny fileno/dup fix | ✅ FIXED | + +**Local server test results: 18/18 pass (0 failures, 0 timeouts)** + +| Test File | Result | Notes | +|-----------|--------|-------| +| t/local/back.t | 47/47 | ✅ | +| t/local/get.t | 34/34 | ✅ (including redirect test) | +| t/local/click.t | 9/9 | ✅ | +| t/local/click_button.t | 15/15 | ✅ | +| t/local/content.t | 3/3 | ✅ | +| t/local/encoding.t | 6/6 | ✅ | +| t/local/failure.t | 15/15 | ✅ | +| t/local/follow.t | 32/32 | ✅ | +| t/local/form.t | 38/38 | ✅ | +| t/local/head.t | 8/8 | ✅ | +| t/local/nonascii.t | 5/5 | ✅ | +| t/local/overload.t | SKIP | Test skips itself | +| t/local/page_stack.t | 26/26 | ✅ | +| t/local/post.t | 5/5 | ✅ | +| t/local/referer.t | 14/14 | ✅ | +| t/local/reload.t | 15/15 | ✅ | +| t/local/select_multiple.t | 19/19 | ✅ | +| t/local/submit.t | 13/13 | ✅ | +| t/history.t | 27/27 | ✅ | +| cookies.t | TIMEOUT | Needs TestServer fork-open pattern | + +### Remaining Issues + +1. **cookies.t** — Uses `TestServer.pm` which requires `open FH, '-|'` fork-open pattern + (no exec). This is a true fork dependency that can't be worked around. + +2. ~~**XHTML marked_sections** — find_link_xhtml.t (2 failures).~~ ✅ FIXED in Phase 11. + +3. ~~**CSS background-url extraction** — image-parse.t (1 failure).~~ ✅ FIXED in Phase 11. + +4. **`getGlobHash()` auto-vivification** — `${*$gensym}{"key"}` still auto-vivifies stash + entries via `GlobalVariable.getGlobalHash()` because the gensym'd glob's `hashSlot` is + null (RuntimeStashEntry.createReference() stores the original stash entry, not a detached + copy). This doesn't affect IO closing but is a correctness issue. Low priority. + +--- + +## Phase 8: Capture::Tiny capture* Implementation — COMPLETE + +### Problem + +Capture::Tiny's `capture`, `capture_stdout`, `capture_stderr`, `capture_merged` functions +don't need fork — they work by dup'ing STDOUT/STDERR to temp files, running user code, +then restoring. But they fail because `fileno()` returns undef for regular file handles. + +### Capture::Tiny capture* flow (non-fork path) + +``` +_capture_tee($do_stdout, $do_stderr, $do_merge, $do_tee=0, $code): + 1. _copy_std() → open $save, ">&STDOUT" (dup by name — WORKS) + 2. File::Temp->new → $stash->{new}{stdout} = tmpfile + 3. _open_std() → open *STDOUT, ">&" . fileno($tmpfile) ← FAILS (fileno=undef) + 4. $code->() → user code prints to redirected STDOUT + 5. _open_std() → open *STDOUT, ">&" . fileno($save) ← FAILS (fileno=undef) + 6. _slurp() → seek + readline on tmpfile +``` + +### Root cause: 4 bugs in fileno/dup chain + +#### Bug 13: `CustomFileChannel.fileno()` returns undef +- **File**: `CustomFileChannel.java:367-368` +- **Impact**: `fileno($tmpfile)` returns undef for ALL regular file handles +- **Fix**: Remove the hardcoded undef return. `RuntimeIO.fileno()` already checks + `getAssignedFileno()` first (which returns the registered fd), so if we assign filenos + at file open time, `CustomFileChannel.fileno()` is never reached. But as a safety net, + delegate to the RuntimeIO registry. + +#### Bug 14: Regular file handles never get assigned filenos +- **File**: `RuntimeIO.java` — `open()` methods that create `CustomFileChannel` +- **Impact**: Even though `assignFileno()` exists, it's only called for sockets +- **Fix**: Call `this.assignFileno()` after creating any new IOHandle (CustomFileChannel, + PipeOutputChannel, PipeInputChannel). This populates the `filenoToIO`/`ioToFileno` + registries so `RuntimeIO.fileno()` returns a valid fd. + +#### Bug 15: `findFileHandleByDescriptor()` doesn't check RuntimeIO's fileno registry +- **File**: `IOOperator.java:2473-2491` +- **Impact**: Even if fileno returns a valid number, `open *STDOUT, ">&3"` can't find the + handle because `findFileHandleByDescriptor()` only checks its own `fileDescriptorMap` + (which is never populated) and the hardcoded stdin/stdout/stderr cases. +- **Fix**: In the `default` case, also check `RuntimeIO.getByFileno(fd)`. + +#### Bug 16: Empty fd in dup mode silently corrupts STDOUT +- **File**: `RuntimeIO.java:449-458` +- **Impact**: When fileno returns undef, `">&" . undef` becomes `">&"`. The 2-arg open + parses this as mode=">&" with empty filename, which falls through to a code path that + replaces the handle with `new StandardIO(System.in)` — STDOUT becomes a stdin reader! +- **Fix**: In the `-`/empty filename branch, check if mode contains `&` and return an error + instead of silently corrupting the handle. + +### Implementation steps + +1. In `RuntimeIO.java`, after every `new CustomFileChannel(...)`, call `this.assignFileno()` +2. In `RuntimeIO.java`, after `openPipe()` creates pipe handles, call `assignFileno()` +3. In `IOOperator.findFileHandleByDescriptor()`, add `RuntimeIO.getByFileno(fd)` fallback +4. In `RuntimeIO.open(String)`, add guard for empty filename with dup mode +5. Also call `assignFileno()` in `duplicateFileHandle()` so dup'd handles get their own fd +6. In `RuntimeIO.unassignFileno()` (or close), unregister the fd to prevent leaks + +### Test plan + +```bash +# Quick validation +./jperl -e 'use Capture::Tiny qw(capture); my ($o,$e) = capture { print "hello\n"; warn "err\n" }; print "out=[$o] err=[$e]\n"' + +# WWW::Mechanize dump.t +cd ~/.cpan/build/WWW-Mechanize-2.20-0 && ../../projects/PerlOnJava2/jperl t/dump.t + +# Broader Capture::Tiny tests +./jcpan -t Capture::Tiny +``` + +--- + +## Phase 9: HTTP::Daemon Pure Perl Testing — COMPLETE + +### Problem + +The WWW::Mechanize `t/local/*.t` tests (18 files) and `t/cookies.t` need a local HTTP server. +HTTP::Daemon is pure Perl on `IO::Socket::IP` and does NOT use fork itself. + +### Analysis: What HTTP::Daemon needs vs PerlOnJava support + +| Feature | Status | Notes | +|---------|--------|-------| +| `IO::Socket::IP->new(Listen=>N)` | ✅ Works | socket/bind/listen chain | +| `accept($new, $sock)` builtin | ✅ Works | `IOOperator.java:1838` | +| `${*$self}{'key'}` glob hash stash | ✅ Works | `RuntimeGlob.getGlobHash()` | +| `vec($fdset, fileno, 1) = 1` | ✅ Works | lvalue vec + small sequential filenos | +| 4-arg `select()` | ✅ Works | `IOOperator.selectWithNIO()` | +| `sysread($fh, $buf, N, offset)` | ✅ Works | 4-arg sysread with offset | +| `print $fh "data"` | ✅ Works | write to socket glob | +| `fileno($sock)` | ✅ Works | small sequential integers from registry | +| `getsockopt(SO_TYPE)` | ⚠️ Returns 0 | Not mapped in `SocketIO.mapToJavaSocketOption()` | +| `getaddrinfo(undef, "0", ...)` | ⚠️ Needs test | Ephemeral port binding | + +### Test harness patterns + +| Harness | Pattern | PerlOnJava Support | +|---------|---------|-------------------| +| `LocalServer.pm` (18 tests) | `open $fh, qq'$^X "log-server" ...\|'` | ✅ Piped open works | +| `TestServer.pm` (cookies.t) | `open $fh, '-\|'` (fork-open, no exec) | ❌ Needs true fork | + +### Implementation steps + +1. Test `HTTP::Daemon->new` — does it create a listening socket? +2. Test `$d->accept` — does it return a blessed `HTTP::Daemon::ClientConn`? +3. Test glob stash `${*$sock}{'httpd_daemon'}` on the accepted connection +4. Test full `get_request()` + `send_response()` cycle +5. Test `LocalServer::spawn()` end-to-end +6. If `getsockopt(SO_TYPE)` is needed: store socket type during creation, return from + `getSocketOption(SOL_SOCKET, SO_TYPE)` — ~10 lines in `SocketIO.java` + +### Test plan + +```bash +# Step 1: Basic HTTP::Daemon +./jperl -e 'use HTTP::Daemon; my $d = HTTP::Daemon->new or die $!; print $d->url, "\n"; print "OK\n"' + +# Step 2: Accept + serve (manual test with curl) +./jperl -e ' + use HTTP::Daemon; + use HTTP::Response; + my $d = HTTP::Daemon->new or die; + print STDERR "Listening at: ", $d->url, "\n"; + my $c = $d->accept or die; + my $r = $c->get_request or die; + $c->send_response(HTTP::Response->new(200, "OK", undef, "Hello World\n")); + $c->close; +' +# Then in another terminal: curl http://localhost:/ + +# Step 3: LocalServer spawn (the real test) +cd ~/.cpan/build/WWW-Mechanize-2.20-0 && ../../projects/PerlOnJava2/jperl t/local/get.t +``` + +### Bug 11: HTMLParser script/style raw text handling (FIXED) +- **File**: `HTMLParser.java:parseHtml()` +- **Symptom**: Tags inside ` regardless of case. + */ + private static int findCaseInsensitive(String haystack, String needle, int fromIndex) { + int needleLen = needle.length(); + int limit = haystack.length() - needleLen; + for (int i = fromIndex; i <= limit; i++) { + if (haystack.regionMatches(true, i, needle, 0, needleLen)) { + // Make sure the next char after the tag name is > or whitespace or / + int afterName = i + needleLen; + if (afterName >= haystack.length() || haystack.charAt(afterName) == '>' + || Character.isWhitespace(haystack.charAt(afterName)) + || haystack.charAt(afterName) == '/') { + return i; + } + } + } + return -1; + } + + /** + * Find end tag for raw text elements (like ) while skipping CDATA sections. + * When marked_sections is enabled, inside is not a real end tag. + */ + private static int findEndTagSkippingCdata(String haystack, String endTag, int fromIndex) { + int pos = fromIndex; + int len = haystack.length(); + while (pos < len) { + // Look for = 0 && cdataStart < tagIdx) { + // CDATA section starts before the end tag - skip past ]]> + int cdataEnd = haystack.indexOf("]]>", cdataStart + 9); + if (cdataEnd >= 0) { + pos = cdataEnd + 3; + continue; + } else { + // Unterminated CDATA section - no end tag found + return -1; + } + } + + // End tag is not inside a CDATA section + return tagIdx; + } + return -1; + } + // ================================================================ // Entity decoding core (ported from util.c decode_entities) // ================================================================ diff --git a/src/main/java/org/perlonjava/runtime/perlmodule/Universal.java b/src/main/java/org/perlonjava/runtime/perlmodule/Universal.java index 113f192d5..dbbeb1bb7 100644 --- a/src/main/java/org/perlonjava/runtime/perlmodule/Universal.java +++ b/src/main/java/org/perlonjava/runtime/perlmodule/Universal.java @@ -244,6 +244,7 @@ public static RuntimeList isa(RuntimeArray args, int ctx) { case GLOBREFERENCE: case FORMAT: case REGEX: + case CODE: int blessId = ((RuntimeBase) object.value).blessId; if (blessId == 0) { return getScalarBoolean( @@ -253,6 +254,7 @@ public static RuntimeList isa(RuntimeArray args, int ctx) { || type == GLOBREFERENCE && argString.equals("GLOB") || type == FORMAT && argString.equals("FORMAT") || type == REGEX && argString.equals("Regexp") + || type == CODE && argString.equals("CODE") ).getList(); } perlClassName = NameNormalizer.getBlessStr(blessId); diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalVariable.java b/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalVariable.java index 42177e3c8..ad72d3f21 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalVariable.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalVariable.java @@ -718,6 +718,18 @@ public static boolean isGlobalIODefined(String key) { return false; } + /** + * Returns the existing global IO glob for the given key, or null if not present. + * Unlike {@link #getGlobalIO(String)}, this method does NOT auto-create entries. + * Used by closeIOOnDrop() to check if a glob is still in the stash. + * + * @param key The key of the global IO reference. + * @return The RuntimeGlob if it exists in the stash, null otherwise. + */ + public static RuntimeGlob getExistingGlobalIO(String key) { + return globalIORefs.get(key); + } + /** * Checks if a glob is defined (has any slot initialized). * Used for `defined *$var` which should not throw strict refs and not auto-vivify. diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/OverloadContext.java b/src/main/java/org/perlonjava/runtime/runtimetypes/OverloadContext.java index 19d95702e..79bcfb260 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/OverloadContext.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/OverloadContext.java @@ -1,6 +1,7 @@ package org.perlonjava.runtime.runtimetypes; import org.perlonjava.runtime.mro.InheritanceResolver; +import org.perlonjava.runtime.runtimetypes.RuntimeCode; import java.util.function.Function; @@ -392,7 +393,16 @@ private RuntimeScalar resolveOverloadMethodName(String methodName, RuntimeArray // The actual method name - find it using can() semantics // (search in the object's class hierarchy) - return InheritanceResolver.findMethodInHierarchy(actualMethodName, perlClassName, null, 0); + RuntimeScalar resolved = InheritanceResolver.findMethodInHierarchy(actualMethodName, perlClassName, null, 0); + // If AUTOLOAD was resolved instead of the actual method, set $AUTOLOAD + if (resolved != null && resolved.value instanceof RuntimeCode) { + RuntimeCode code = (RuntimeCode) resolved.value; + if (code.autoloadVariableName != null) { + String fullMethodName = NameNormalizer.normalizeVariableName(actualMethodName, perlClassName); + GlobalVariable.getGlobalVariable(code.autoloadVariableName).set(fullMethodName); + } + } + return resolved; } } } diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeIO.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeIO.java index 030fcb78b..e56ec766c 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeIO.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeIO.java @@ -21,6 +21,9 @@ Handling pipes (e.g., |- or -| modes). import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; @@ -29,6 +32,7 @@ Handling pipes (e.g., |- or -| modes). import static org.perlonjava.runtime.runtimetypes.GlobalVariable.getGlobalIO; import static org.perlonjava.runtime.runtimetypes.GlobalVariable.getGlobalVariable; import static org.perlonjava.runtime.runtimetypes.RuntimeScalarCache.scalarFalse; +import static org.perlonjava.runtime.runtimetypes.RuntimeScalarCache.scalarTrue; import static org.perlonjava.runtime.runtimetypes.RuntimeScalarCache.scalarUndef; /** @@ -136,9 +140,20 @@ protected boolean removeEldestEntry(Map.Entry eldest) { /** * Fileno registry for select() support. - * Maps small sequential integers to RuntimeIO objects, allowing - * 4-arg select() to find handles from bit-vector fileno values. - * Standard fds 0-2 are reserved for stdin/stdout/stderr. + *

+ * Maps small sequential integers ("virtual fds") to RuntimeIO objects, + * allowing 4-arg select() to find handles from bit-vector fileno values + * and dup-by-fd operations like {@code open(*STDOUT, ">&3")}. + *

+ * Standard fds 0-2 are reserved for stdin/stdout/stderr and are handled + * natively by StandardIO (not through this registry). + *

+ * Fd recycling: Freed fds are collected in a queue and reused by + * {@code assignFileno()} (lowest available first) to mimic OS fd allocation. + * This is safe because fds are only freed on explicit {@code close()} — + * the eager {@code closeIOOnDrop()} was removed from variable assignment + * (see RuntimeScalar.setLarge), so fds are never prematurely freed while + * other variables still reference the handle. */ private static final AtomicInteger nextFileno = new AtomicInteger(3); private static final ConcurrentHashMap filenoToIO = new ConcurrentHashMap<>(); @@ -147,29 +162,130 @@ protected boolean removeEldestEntry(Map.Entry eldest) { * so we must do the same to pass tests like io/perlio_leaks.t that verify fd recycling. */ private static final ConcurrentLinkedQueue recycledFds = new ConcurrentLinkedQueue<>(); + /** + * GC-based fd recycling for anonymous lexical filehandles. + *

+ * In Perl 5, lexical filehandles ({@code my $fh}) are closed via DESTROY + * when the SV's refcount drops to zero at scope exit. PerlOnJava doesn't + * implement DESTROY or reference counting; the JVM uses tracing GC instead. + *

+ * To reclaim fds from abandoned lexical handles, we register a + * {@link PhantomReference} on the anonymous {@link RuntimeGlob} created by + * {@code open(my $fh, ...)}. When the glob becomes phantom-reachable (all + * RuntimeScalars referencing it have been abandoned), the PhantomReference + * is enqueued. {@link #processAbandonedGlobs()} polls this queue, closes + * the associated RuntimeIO, and frees the fd for reuse. + *

+ * {@code processAbandonedGlobs()} is called from {@link #assignFileno()}. + * If no recycled fds are available, {@code System.gc()} is called as a hint + * to encourage the JVM to enqueue phantom references sooner. + */ + private static final ReferenceQueue globGCQueue = new ReferenceQueue<>(); + private static final ConcurrentHashMap, RuntimeIO> phantomToIO = new ConcurrentHashMap<>(); + + /** + * Registers an anonymous RuntimeGlob for GC-based fd recycling. + * When the glob becomes unreachable (all variables referencing it are + * reassigned or go out of scope), the associated RuntimeIO will be + * closed and its fd freed. + * + * @param glob the anonymous RuntimeGlob to track + * @param io the RuntimeIO whose fd should be freed when the glob is collected + */ + public static void registerGlobForFdRecycling(RuntimeGlob glob, RuntimeIO io) { + PhantomReference phantom = new PhantomReference<>(glob, globGCQueue); + phantomToIO.put(phantom, io); + } + + /** + * Processes the GC reference queue: closes RuntimeIO handles whose + * parent RuntimeGlob has been collected, freeing their fds for reuse. + */ + public static void processAbandonedGlobs() { + Reference ref; + while ((ref = globGCQueue.poll()) != null) { + RuntimeIO io = phantomToIO.remove(ref); + if (io != null && !(io.ioHandle instanceof ClosedIOHandle)) { + io.close(); + } + } + } + /** * Assigns a fileno to this RuntimeIO and registers it in the fd→IO maps. * Reuses released fd numbers when available (lowest first via the recycle pool), * otherwise allocates the next sequential fd. This matches POSIX semantics where * close() releases an fd and the next open() reuses the lowest available fd. + *

+ * If this RuntimeIO already has an assigned fileno, returns it (idempotent). + * Called eagerly from {@code duplicateFileHandle()} for dup'd handles + * (so dup-by-fd like {@code open(*FH, ">&3")} can find them), and lazily + * from {@code fileno()} for regular file/pipe handles. * - * @return the assigned fileno + * @return the assigned fileno (always >= 3) */ public int assignFileno() { Integer existing = ioToFileno.get(this); if (existing != null) { return existing; } - // Try to reuse a recycled fd first (POSIX: lowest available) - Integer recycled = recycledFds.poll(); - int fd = (recycled != null) ? recycled : nextFileno.getAndIncrement(); + // First, process any GC'd globs to free their fds + processAbandonedGlobs(); + // Try to reuse the lowest freed fd + int fd = tryRecycleLowestFd(); + if (fd >= 0) { + filenoToIO.put(fd, this); + ioToFileno.put(this, fd); + FileDescriptorTable.advancePast(fd); + return fd; + } + // No recycled fds — if there are tracked anonymous globs that might + // be collectible, hint the GC and retry a few times with short sleeps + // to give the ReferenceHandler thread time to process the queue. + if (!phantomToIO.isEmpty()) { + for (int attempt = 0; attempt < 5; attempt++) { + System.gc(); + try { Thread.sleep(1); } catch (InterruptedException e) { break; } + processAbandonedGlobs(); + fd = tryRecycleLowestFd(); + if (fd >= 0) { + filenoToIO.put(fd, this); + ioToFileno.put(this, fd); + FileDescriptorTable.advancePast(fd); + return fd; + } + } + } + // Allocate a fresh fd + fd = nextFileno.getAndIncrement(); filenoToIO.put(fd, this); ioToFileno.put(this, fd); - // Keep FileDescriptorTable in sync to prevent fd collisions with pipe() FileDescriptorTable.advancePast(fd); return fd; } + /** + * Tries to recycle the lowest available freed fd. + * Returns -1 if none available. + */ + private static int tryRecycleLowestFd() { + List candidates = new ArrayList<>(); + Integer recycled; + while ((recycled = recycledFds.poll()) != null) { + candidates.add(recycled); + } + if (candidates.isEmpty()) { + return -1; + } + Collections.sort(candidates); + int fd = candidates.get(0); + // Put back the rest + for (int i = 1; i < candidates.size(); i++) { + recycledFds.add(candidates.get(i)); + } + return fd; + } + /** * Gets the assigned fileno for this RuntimeIO, or -1 if not assigned. */ @@ -488,6 +604,13 @@ public static RuntimeIO open(String fileName) { // Handle special filenames if ("-".equals(actualFileName) || actualFileName.isEmpty()) { + if (mode.contains("&")) { + // Empty fd in dup mode (e.g., ">&" with no fd number) is an error. + // This happens when fileno() returns undef and the caller does + // open(*STDOUT, ">&" . fileno($fh)) — the undef concatenates to ">&". + handleIOError("Bad file descriptor"); + return null; + } if (mode.equals(">") || mode.equals(">>")) { // ">-" or just ">" means stdout fh.ioHandle = new CustomOutputStreamHandle(System.out); @@ -575,6 +698,8 @@ public static RuntimeIO open(String fileName, String mode) { // Initialize ioHandle with CustomFileChannel fh.ioHandle = new CustomFileChannel(filePath, options); + // Fileno is assigned lazily when fileno() is called + // Add the handle to the LRU cache addHandle(fh.ioHandle); @@ -773,6 +898,8 @@ public static RuntimeIO openPipe(RuntimeList runtimeList) { return null; } + // Fileno is assigned lazily when fileno() is called + // Add the handle to the LRU cache addHandle(fh.ioHandle); @@ -969,7 +1096,7 @@ public static RuntimeIO getRuntimeIO(RuntimeScalar runtimeScalar) { System.err.println("[JPERL_IO_DEBUG] getRuntimeIO: fallback lookup for " + runtimeGlob.globName); System.err.flush(); } - RuntimeGlob globalGlob = GlobalVariable.getGlobalIO(runtimeGlob.globName); + RuntimeGlob globalGlob = GlobalVariable.getExistingGlobalIO(runtimeGlob.globName); if (globalGlob != null) { RuntimeScalar globalIoScalar = globalGlob.getIO(); if (globalIoScalar != null) { @@ -1228,17 +1355,18 @@ public boolean getBooleanRef() { /** * Closes this I/O handle. * Removes from cache, flushes buffers, and releases resources. + *

+ * For borrowed handles (parsimonious dup), only detaches from the ioHandle + * without flushing or closing it — the owning handle will handle cleanup. * * @return RuntimeScalar indicating success/failure */ public RuntimeScalar close() { removeHandle(ioHandle); + unregisterFileno(); ioHandle.flush(); RuntimeScalar ret = ioHandle.close(); ioHandle = new ClosedIOHandle(); - // Release our fd back to the recycle pool so it can be reused by future opens. - // This must happen AFTER close so that the fd is still valid during the close. - unregisterFileno(); return ret; } @@ -1362,11 +1490,22 @@ public RuntimeScalar write(String data) { /** * Gets the file descriptor number for this handle. + *

+ * Resolution order: + *

    + *
  1. Check the fileno registry (for handles that already have an assigned fd)
  2. + *
  3. Ask the ioHandle for its native fd (StandardIO returns 0/1/2)
  4. + *
  5. For file channels and pipes, lazily assign a registry fd on first call — + * this avoids consuming fd numbers for handles whose fileno is never queried
  6. + *
+ *

+ * The lazy assignment strategy is important for modules like Capture::Tiny + * that open many temporary file handles but only need fileno() on a few. * * @return RuntimeScalar with the file descriptor number, or undef if not available */ public RuntimeScalar fileno() { - // Check registry first — socket handles get small sequential filenos + // Check registry first — already-assigned handles int fd = getAssignedFileno(); if (fd >= 0) { return new RuntimeScalar(fd); @@ -1374,7 +1513,21 @@ public RuntimeScalar fileno() { if (ioHandle == null) { return RuntimeScalarCache.scalarUndef; } - return ioHandle.fileno(); + // Try the native fileno first (StandardIO returns 0/1/2) + RuntimeScalar nativeFd = ioHandle.fileno(); + if (nativeFd.getDefinedBoolean()) { + return nativeFd; + } + // For file channels and pipes, lazily assign a registry fileno + if (ioHandle instanceof CustomFileChannel + || ioHandle instanceof PipeInputChannel + || ioHandle instanceof PipeOutputChannel + || ioHandle instanceof InternalPipeHandle + || ioHandle instanceof LayeredIOHandle) { + fd = assignFileno(); + return new RuntimeScalar(fd); + } + return RuntimeScalarCache.scalarUndef; } /** diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeScalar.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeScalar.java index 9fb0f366a..42eb7624b 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeScalar.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeScalar.java @@ -1,6 +1,7 @@ package org.perlonjava.runtime.runtimetypes; import org.perlonjava.frontend.parser.NumberParser; +import org.perlonjava.runtime.io.ClosedIOHandle; import org.perlonjava.runtime.mro.InheritanceResolver; import org.perlonjava.runtime.operators.StringOperators; import org.perlonjava.runtime.operators.WarnDie; @@ -725,6 +726,7 @@ public RuntimeScalar set(RuntimeScalar value) { // Slow path for set(RuntimeScalar) private RuntimeScalar setLarge(RuntimeScalar value) { if (value == null) { + closeIOOnDrop(); this.type = RuntimeScalarType.UNDEF; this.value = null; return this; @@ -750,6 +752,39 @@ private RuntimeScalar setLarge(RuntimeScalar value) { case READONLY_SCALAR -> throw new PerlCompilerException("Modification of a read-only value attempted"); } + // ────────────────────────────────────────────────────────────────── + // closeIOOnDrop() was REMOVED from this assignment path. + // + // ROOT CAUSE (Capture::Tiny failure): + // Capture::Tiny's _copy_std() saves STDOUT/STDERR handles like this: + // my $h; + // $h = IO::Handle->new(); open($h, ">&STDOUT"); $old{stdout} = $h; + // $h = IO::Handle->new(); open($h, ">&STDERR"); $old{stderr} = $h; + // + // When $h is reassigned on the second iteration, setLarge() was called. + // The old value of $h was a GLOBREFERENCE to a gensym'd glob (Symbol::GEN*) + // whose IO slot held the dup'd STDOUT handle. + // + // closeIOOnDrop() saw that the glob was no longer in any stash (gensym + // deletes it) and closed the IO. This set ioHandle = ClosedIOHandle on + // the RuntimeIO. But $old{stdout} STILL referenced the same glob/IO — + // so fileno($old{stdout}) now returned undef, and the later restore + // open(*STDOUT, ">&" . fileno($old{stdout})) failed with "Bad fd". + // + // WHY WE CAN'T FIX THIS WITH closeIOOnDrop: + // Without reference counting we cannot know whether other variables + // still hold a GLOBREFERENCE to the same RuntimeGlob. The stash check + // only catches named globs; anonymous (gensym'd) globs are invisible. + // + // TRADEOFF: + // Removing this call means anonymous file handles that are overwritten + // (not explicitly closed) will leak until JVM GC / program exit. + // Explicit close($fh), undef $fh, and program exit still close handles. + // This matches the pre-existing behavior of set(int/long/double/String) + // which also never called closeIOOnDrop. + // + // See also: closeIOOnDrop() javadoc, dev/design/io_handle_lifecycle.md + // ────────────────────────────────────────────────────────────────── this.type = value.type; this.value = value.value; return this; @@ -1660,12 +1695,96 @@ public RuntimeScalar undefine() { InheritanceResolver.invalidateCache(); return this; } + // Close IO handles when dropping a glob reference. + // This mimics Perl's internal sv_clear behavior where IO handles are closed + // when the glob's reference count drops to zero (independent of DESTROY). + closeIOOnDrop(); // For all other types, set to undef this.type = UNDEF; this.value = null; return this; } + /** + * Close any IO handle associated with a GLOBREFERENCE value being dropped. + *

+ * In Perl 5, IO handles are closed by the interpreter's sv_clear/gp_free when + * the glob's reference count reaches zero. Since jperl doesn't implement + * reference counting or DESTROY, we close IO handles eagerly in specific cases. + *

+ * Where this is called: + *

    + *
  • {@code undefine()} — when {@code undef $fh} is called explicitly
  • + *
  • {@code setLarge(null)} — when a variable is set to null/undef
  • + *
+ *

+ * Where this is NOT called (by design): + *

    + *
  • {@code setLarge(value)} for non-null values — removed because variable + * reassignment (e.g. {@code $h = IO::Handle->new()}) cannot safely close + * the old IO when other variables may still reference the same glob. + * See the detailed comment in setLarge() for the Capture::Tiny failure + * that motivated this change.
  • + *
  • {@code set(int/long/double/String)} — these primitive-type setters + * never called closeIOOnDrop (pre-existing behavior).
  • + *
+ *

+ * Safety heuristic: We only close IO for globs that are NOT currently + * in any stash (symbol table). Named globs still in the stash (like *MYFILE) + * may have other references (including detached copies created by + * {@code \*MYFILE}) and should not be closed. Globs that have been removed + * from the stash (e.g., by gensym's delete) or that were never in a stash + * are candidates for closing — but even this is only safe from undefine() + * where the caller is explicitly requesting cleanup. + *

+ * Known limitation: Without reference counting, anonymous file handles + * that are overwritten (not explicitly closed or undef'd) will leak their + * underlying IO until JVM garbage collection or program exit. + */ + private void closeIOOnDrop() { + if (type == GLOBREFERENCE && value instanceof RuntimeGlob glob) { + // If the glob has a name and a stash entry still exists for that name, + // don't close — the IO may be shared with the stash glob or its copies. + // Note: \*MYFILE creates a detached copy (different Java object) that + // shares the IO slot, so identity checks don't work here. + if (glob.globName != null && GlobalVariable.existsGlobalIO(glob.globName)) { + return; // Glob name is still in the stash — don't close + } + RuntimeScalar ioSlot = glob.getIO(); + if (ioSlot != null && ioSlot.value instanceof RuntimeIO io + && !(io.ioHandle instanceof ClosedIOHandle)) { + io.close(); + } + } + } + + /** + * Called by JVM bytecode at scope exit to deterministically close IO handles + * on anonymous lexical filehandles ({@code open(my $fh, ...)}). + *

+ * This is the JVM-backend equivalent of Perl 5's DESTROY: when a {@code my $fh} + * goes out of scope, its IO handle should be closed and its fd recycled. + * Since the JVM's tracing GC is non-deterministic, we call this explicitly + * from the emitted scope-exit bytecode to ensure timely fd recycling. + *

+ * Only closes IO on anonymous globs (globName == null) — named globs like + * {@code *STDOUT} or gensym'd handles may be referenced by other variables + * (e.g., in Capture::Tiny's save/restore pattern). + * + * @param scalar the RuntimeScalar being cleaned up (may be null if slot was already nulled) + */ + public static void scopeExitCleanup(RuntimeScalar scalar) { + if (scalar != null && scalar.type == GLOBREFERENCE + && scalar.value instanceof RuntimeGlob glob + && glob.globName == null) { + RuntimeScalar ioSlot = glob.getIO(); + if (ioSlot != null && ioSlot.value instanceof RuntimeIO io + && !(io.ioHandle instanceof ClosedIOHandle)) { + io.close(); + } + } + } + public RuntimeScalar defined() { return getScalarBoolean(getDefinedBoolean()); } diff --git a/src/main/perl/lib/Devel/Cycle.pm b/src/main/perl/lib/Devel/Cycle.pm new file mode 100644 index 000000000..720a3f370 --- /dev/null +++ b/src/main/perl/lib/Devel/Cycle.pm @@ -0,0 +1,35 @@ +package Devel::Cycle; +use strict; +use warnings; + +our $VERSION = '1.12'; + +# No-op stub for PerlOnJava. +# The JVM uses tracing GC which handles circular references natively. +# Cycles are never a problem, so find_cycle always reports zero cycles. + +use Exporter qw(import); + +our @EXPORT = qw(find_cycle find_weakened_cycle); +our @EXPORT_OK = @EXPORT; + +# Never calls callback = no cycles found +sub find_cycle { } +sub find_weakened_cycle { } + +1; + +__END__ + +=head1 NAME + +Devel::Cycle - No-op stub for PerlOnJava + +=head1 DESCRIPTION + +This is a no-op implementation of Devel::Cycle for PerlOnJava. +The JVM uses tracing garbage collection which handles circular +references natively, so cycle detection is unnecessary. +C and C always report zero cycles. + +=cut diff --git a/src/main/perl/lib/LWP/media.types b/src/main/perl/lib/LWP/media.types new file mode 100644 index 000000000..6a90929c0 --- /dev/null +++ b/src/main/perl/lib/LWP/media.types @@ -0,0 +1,1479 @@ +# This file maps Internet media types to unique file extension(s). +# Although created for httpd, this file is used by many software systems +# and has been placed in the public domain for unlimited redisribution. +# +# The table below contains both registered and (common) unregistered types. +# A type that has no unique extension can be ignored -- they are listed +# here to guide configurations toward known types and to make it easier to +# identify "new" types. File extensions are also commonly used to indicate +# content languages and encodings, so choose them carefully. +# +# Internet media types should be registered as described in RFC 4288. +# The registry is at . +# +# MIME type (lowercased) Extensions +# ============================================ ========== +# application/1d-interleaved-parityfec +# application/3gpp-ims+xml +# application/activemessage +application/andrew-inset ez +# application/applefile +application/applixware aw +application/atom+xml atom +application/atomcat+xml atomcat +# application/atomicmail +application/atomsvc+xml atomsvc +# application/auth-policy+xml +# application/batch-smtp +# application/beep+xml +# application/cals-1840 +application/ccxml+xml ccxml +application/cdmi-capability cdmia +application/cdmi-container cdmic +application/cdmi-domain cdmid +application/cdmi-object cdmio +application/cdmi-queue cdmiq +# application/cea-2018+xml +# application/cellml+xml +# application/cfw +# application/cnrp+xml +# application/commonground +# application/conference-info+xml +# application/cpl+xml +# application/csta+xml +# application/cstadata+xml +application/cu-seeme cu +# application/cybercash +application/davmount+xml davmount +# application/dca-rft +# application/dec-dx +# application/dialog-info+xml +# application/dicom +# application/dns +# application/dskpp+xml +application/dssc+der dssc +application/dssc+xml xdssc +# application/dvcs +application/ecmascript ecma +# application/edi-consent +# application/edi-x12 +# application/edifact +application/emma+xml emma +# application/epp+xml +application/epub+zip epub +# application/eshop +# application/example +application/exi exi +# application/fastinfoset +# application/fastsoap +# application/fits +application/font-tdpfr pfr +# application/framework-attributes+xml +# application/h224 +# application/held+xml +# application/http +application/hyperstudio stk +# application/ibe-key-request+xml +# application/ibe-pkg-reply+xml +# application/ibe-pp-data +# application/iges +# application/im-iscomposing+xml +# application/index +# application/index.cmd +# application/index.obj +# application/index.response +# application/index.vnd +# application/iotp +application/ipfix ipfix +# application/ipp +# application/isup +application/java-archive jar +application/java-serialized-object ser +application/java-vm class +application/javascript js +application/json json +# application/kpml-request+xml +# application/kpml-response+xml +application/lost+xml lostxml +application/mac-binhex40 hqx +application/mac-compactpro cpt +# application/macwriteii +application/mads+xml mads +application/marc mrc +application/marcxml+xml mrcx +application/mathematica ma nb mb +# application/mathml-content+xml +# application/mathml-presentation+xml +application/mathml+xml mathml +# application/mbms-associated-procedure-description+xml +# application/mbms-deregister+xml +# application/mbms-envelope+xml +# application/mbms-msk+xml +# application/mbms-msk-response+xml +# application/mbms-protection-description+xml +# application/mbms-reception-report+xml +# application/mbms-register+xml +# application/mbms-register-response+xml +# application/mbms-user-service-description+xml +application/mbox mbox +# application/media_control+xml +application/mediaservercontrol+xml mscml +application/metalink4+xml meta4 +application/mets+xml mets +# application/mikey +application/mods+xml mods +# application/moss-keys +# application/moss-signature +# application/mosskey-data +# application/mosskey-request +application/mp21 m21 mp21 +application/mp4 mp4s +# application/mpeg4-generic +# application/mpeg4-iod +# application/mpeg4-iod-xmt +# application/msc-ivr+xml +# application/msc-mixer+xml +application/msword doc dot +application/mxf mxf +# application/nasdata +# application/news-checkgroups +# application/news-groupinfo +# application/news-transmission +# application/nss +# application/ocsp-request +# application/ocsp-response +application/octet-stream bin dms lha lrf lzh so iso dmg dist distz pkg bpk dump elc deploy +application/oda oda +application/oebps-package+xml opf +application/ogg ogx +application/onenote onetoc onetoc2 onetmp onepkg +# application/parityfec +application/patch-ops-error+xml xer +application/pdf pdf +application/pgp-encrypted pgp +# application/pgp-keys +application/pgp-signature asc sig +application/pics-rules prf +# application/pidf+xml +# application/pidf-diff+xml +application/pkcs10 p10 +application/pkcs7-mime p7m p7c +application/pkcs7-signature p7s +application/pkcs8 p8 +application/pkix-attr-cert ac +application/pkix-cert cer +application/pkix-crl crl +application/pkix-pkipath pkipath +application/pkixcmp pki +application/pls+xml pls +# application/poc-settings+xml +application/postscript ai eps ps +# application/prs.alvestrand.titrax-sheet +application/prs.cww cww +# application/prs.nprend +# application/prs.plucker +# application/prs.rdf-xml-crypt +# application/prs.xsf+xml +application/pskc+xml pskcxml +# application/qsig +application/rdf+xml rdf +application/reginfo+xml rif +application/relax-ng-compact-syntax rnc +# application/remote-printing +application/resource-lists+xml rl +application/resource-lists-diff+xml rld +# application/riscos +# application/rlmi+xml +application/rls-services+xml rs +application/rsd+xml rsd +application/rss+xml rss +application/rtf rtf +# application/rtx +# application/samlassertion+xml +# application/samlmetadata+xml +application/sbml+xml sbml +application/scvp-cv-request scq +application/scvp-cv-response scs +application/scvp-vp-request spq +application/scvp-vp-response spp +application/sdp sdp +# application/set-payment +application/set-payment-initiation setpay +# application/set-registration +application/set-registration-initiation setreg +# application/sgml +# application/sgml-open-catalog +application/shf+xml shf +# application/sieve +# application/simple-filter+xml +# application/simple-message-summary +# application/simplesymbolcontainer +# application/slate +# application/smil +application/smil+xml smi smil +# application/soap+fastinfoset +# application/soap+xml +application/sparql-query rq +application/sparql-results+xml srx +# application/spirits-event+xml +application/srgs gram +application/srgs+xml grxml +application/sru+xml sru +application/ssml+xml ssml +# application/tamp-apex-update +# application/tamp-apex-update-confirm +# application/tamp-community-update +# application/tamp-community-update-confirm +# application/tamp-error +# application/tamp-sequence-adjust +# application/tamp-sequence-adjust-confirm +# application/tamp-status-query +# application/tamp-status-response +# application/tamp-update +# application/tamp-update-confirm +application/tei+xml tei teicorpus +application/thraud+xml tfi +# application/timestamp-query +# application/timestamp-reply +application/timestamped-data tsd +# application/tve-trigger +# application/ulpfec +# application/vemmi +# application/vividence.scriptfile +# application/vnd.3gpp.bsf+xml +application/vnd.3gpp.pic-bw-large plb +application/vnd.3gpp.pic-bw-small psb +application/vnd.3gpp.pic-bw-var pvb +# application/vnd.3gpp.sms +# application/vnd.3gpp2.bcmcsinfo+xml +# application/vnd.3gpp2.sms +application/vnd.3gpp2.tcap tcap +application/vnd.3m.post-it-notes pwn +application/vnd.accpac.simply.aso aso +application/vnd.accpac.simply.imp imp +application/vnd.acucobol acu +application/vnd.acucorp atc acutc +application/vnd.adobe.air-application-installer-package+zip air +application/vnd.adobe.fxp fxp fxpl +# application/vnd.adobe.partial-upload +application/vnd.adobe.xdp+xml xdp +application/vnd.adobe.xfdf xfdf +# application/vnd.aether.imp +# application/vnd.ah-barcode +application/vnd.ahead.space ahead +application/vnd.airzip.filesecure.azf azf +application/vnd.airzip.filesecure.azs azs +application/vnd.amazon.ebook azw +application/vnd.americandynamics.acc acc +application/vnd.amiga.ami ami +# application/vnd.amundsen.maze+xml +application/vnd.android.package-archive apk +application/vnd.anser-web-certificate-issue-initiation cii +application/vnd.anser-web-funds-transfer-initiation fti +application/vnd.antix.game-component atx +application/vnd.apple.installer+xml mpkg +application/vnd.apple.mpegurl m3u8 +# application/vnd.arastra.swi +application/vnd.aristanetworks.swi swi +application/vnd.audiograph aep +# application/vnd.autopackage +# application/vnd.avistar+xml +application/vnd.blueice.multipass mpm +# application/vnd.bluetooth.ep.oob +application/vnd.bmi bmi +application/vnd.businessobjects rep +# application/vnd.cab-jscript +# application/vnd.canon-cpdl +# application/vnd.canon-lips +# application/vnd.cendio.thinlinc.clientconf +application/vnd.chemdraw+xml cdxml +application/vnd.chipnuts.karaoke-mmd mmd +application/vnd.cinderella cdy +# application/vnd.cirpack.isdn-ext +application/vnd.claymore cla +application/vnd.cloanto.rp9 rp9 +application/vnd.clonk.c4group c4g c4d c4f c4p c4u +application/vnd.cluetrust.cartomobile-config c11amc +application/vnd.cluetrust.cartomobile-config-pkg c11amz +# application/vnd.commerce-battelle +application/vnd.commonspace csp +application/vnd.contact.cmsg cdbcmsg +application/vnd.cosmocaller cmc +application/vnd.crick.clicker clkx +application/vnd.crick.clicker.keyboard clkk +application/vnd.crick.clicker.palette clkp +application/vnd.crick.clicker.template clkt +application/vnd.crick.clicker.wordbank clkw +application/vnd.criticaltools.wbs+xml wbs +application/vnd.ctc-posml pml +# application/vnd.ctct.ws+xml +# application/vnd.cups-pdf +# application/vnd.cups-postscript +application/vnd.cups-ppd ppd +# application/vnd.cups-raster +# application/vnd.cups-raw +application/vnd.curl.car car +application/vnd.curl.pcurl pcurl +# application/vnd.cybank +application/vnd.data-vision.rdz rdz +application/vnd.dece.data uvf uvvf uvd uvvd +application/vnd.dece.ttml+xml uvt uvvt +application/vnd.dece.unspecified uvx uvvx +application/vnd.denovo.fcselayout-link fe_launch +# application/vnd.dir-bi.plate-dl-nosuffix +application/vnd.dna dna +application/vnd.dolby.mlp mlp +# application/vnd.dolby.mobile.1 +# application/vnd.dolby.mobile.2 +application/vnd.dpgraph dpg +application/vnd.dreamfactory dfac +application/vnd.dvb.ait ait +# application/vnd.dvb.dvbj +# application/vnd.dvb.esgcontainer +# application/vnd.dvb.ipdcdftnotifaccess +# application/vnd.dvb.ipdcesgaccess +# application/vnd.dvb.ipdcesgaccess2 +# application/vnd.dvb.ipdcesgpdd +# application/vnd.dvb.ipdcroaming +# application/vnd.dvb.iptv.alfec-base +# application/vnd.dvb.iptv.alfec-enhancement +# application/vnd.dvb.notif-aggregate-root+xml +# application/vnd.dvb.notif-container+xml +# application/vnd.dvb.notif-generic+xml +# application/vnd.dvb.notif-ia-msglist+xml +# application/vnd.dvb.notif-ia-registration-request+xml +# application/vnd.dvb.notif-ia-registration-response+xml +# application/vnd.dvb.notif-init+xml +# application/vnd.dvb.pfr +application/vnd.dvb.service svc +# application/vnd.dxr +application/vnd.dynageo geo +# application/vnd.easykaraoke.cdgdownload +# application/vnd.ecdis-update +application/vnd.ecowin.chart mag +# application/vnd.ecowin.filerequest +# application/vnd.ecowin.fileupdate +# application/vnd.ecowin.series +# application/vnd.ecowin.seriesrequest +# application/vnd.ecowin.seriesupdate +# application/vnd.emclient.accessrequest+xml +application/vnd.enliven nml +application/vnd.epson.esf esf +application/vnd.epson.msf msf +application/vnd.epson.quickanime qam +application/vnd.epson.salt slt +application/vnd.epson.ssf ssf +# application/vnd.ericsson.quickcall +application/vnd.eszigno3+xml es3 et3 +# application/vnd.etsi.aoc+xml +# application/vnd.etsi.cug+xml +# application/vnd.etsi.iptvcommand+xml +# application/vnd.etsi.iptvdiscovery+xml +# application/vnd.etsi.iptvprofile+xml +# application/vnd.etsi.iptvsad-bc+xml +# application/vnd.etsi.iptvsad-cod+xml +# application/vnd.etsi.iptvsad-npvr+xml +# application/vnd.etsi.iptvservice+xml +# application/vnd.etsi.iptvsync+xml +# application/vnd.etsi.iptvueprofile+xml +# application/vnd.etsi.mcid+xml +# application/vnd.etsi.overload-control-policy-dataset+xml +# application/vnd.etsi.sci+xml +# application/vnd.etsi.simservs+xml +# application/vnd.etsi.tsl+xml +# application/vnd.etsi.tsl.der +# application/vnd.eudora.data +application/vnd.ezpix-album ez2 +application/vnd.ezpix-package ez3 +# application/vnd.f-secure.mobile +application/vnd.fdf fdf +application/vnd.fdsn.mseed mseed +application/vnd.fdsn.seed seed dataless +# application/vnd.ffsns +# application/vnd.fints +application/vnd.flographit gph +application/vnd.fluxtime.clip ftc +# application/vnd.font-fontforge-sfd +application/vnd.framemaker fm frame maker book +application/vnd.frogans.fnc fnc +application/vnd.frogans.ltf ltf +application/vnd.fsc.weblaunch fsc +application/vnd.fujitsu.oasys oas +application/vnd.fujitsu.oasys2 oa2 +application/vnd.fujitsu.oasys3 oa3 +application/vnd.fujitsu.oasysgp fg5 +application/vnd.fujitsu.oasysprs bh2 +# application/vnd.fujixerox.art-ex +# application/vnd.fujixerox.art4 +# application/vnd.fujixerox.hbpl +application/vnd.fujixerox.ddd ddd +application/vnd.fujixerox.docuworks xdw +application/vnd.fujixerox.docuworks.binder xbd +# application/vnd.fut-misnet +application/vnd.fuzzysheet fzs +application/vnd.genomatix.tuxedo txd +# application/vnd.geocube+xml +application/vnd.geogebra.file ggb +application/vnd.geogebra.tool ggt +application/vnd.geometry-explorer gex gre +application/vnd.geonext gxt +application/vnd.geoplan g2w +application/vnd.geospace g3w +# application/vnd.globalplatform.card-content-mgt +# application/vnd.globalplatform.card-content-mgt-response +application/vnd.gmx gmx +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq gqf gqs +# application/vnd.gridmp +application/vnd.groove-account gac +application/vnd.groove-help ghf +application/vnd.groove-identity-message gim +application/vnd.groove-injector grv +application/vnd.groove-tool-message gtm +application/vnd.groove-tool-template tpl +application/vnd.groove-vcard vcg +application/vnd.hal+xml hal +application/vnd.handheld-entertainment+xml zmm +application/vnd.hbci hbci +# application/vnd.hcl-bireports +application/vnd.hhe.lesson-player les +application/vnd.hp-hpgl hpgl +application/vnd.hp-hpid hpid +application/vnd.hp-hps hps +application/vnd.hp-jlyt jlt +application/vnd.hp-pcl pcl +application/vnd.hp-pclxl pclxl +# application/vnd.httphone +application/vnd.hydrostatix.sof-data sfd-hdstx +application/vnd.hzn-3d-crossword x3d +# application/vnd.ibm.afplinedata +# application/vnd.ibm.electronic-media +application/vnd.ibm.minipay mpy +application/vnd.ibm.modcap afp listafp list3820 +application/vnd.ibm.rights-management irm +application/vnd.ibm.secure-container sc +application/vnd.iccprofile icc icm +application/vnd.igloader igl +application/vnd.immervision-ivp ivp +application/vnd.immervision-ivu ivu +# application/vnd.informedcontrol.rms+xml +# application/vnd.informix-visionary +# application/vnd.infotech.project +# application/vnd.infotech.project+xml +application/vnd.insors.igm igm +application/vnd.intercon.formnet xpw xpx +application/vnd.intergeo i2g +# application/vnd.intertrust.digibox +# application/vnd.intertrust.nncp +application/vnd.intu.qbo qbo +application/vnd.intu.qfx qfx +# application/vnd.iptc.g2.conceptitem+xml +# application/vnd.iptc.g2.knowledgeitem+xml +# application/vnd.iptc.g2.newsitem+xml +# application/vnd.iptc.g2.packageitem+xml +application/vnd.ipunplugged.rcprofile rcprofile +application/vnd.irepository.package+xml irp +application/vnd.is-xpr xpr +application/vnd.isac.fcs fcs +application/vnd.jam jam +# application/vnd.japannet-directory-service +# application/vnd.japannet-jpnstore-wakeup +# application/vnd.japannet-payment-wakeup +# application/vnd.japannet-registration +# application/vnd.japannet-registration-wakeup +# application/vnd.japannet-setstore-wakeup +# application/vnd.japannet-verification +# application/vnd.japannet-verification-wakeup +application/vnd.jcp.javame.midlet-rms rms +application/vnd.jisp jisp +application/vnd.joost.joda-archive joda +application/vnd.kahootz ktz ktr +application/vnd.kde.karbon karbon +application/vnd.kde.kchart chrt +application/vnd.kde.kformula kfo +application/vnd.kde.kivio flw +application/vnd.kde.kontour kon +application/vnd.kde.kpresenter kpr kpt +application/vnd.kde.kspread ksp +application/vnd.kde.kword kwd kwt +application/vnd.kenameaapp htke +application/vnd.kidspiration kia +application/vnd.kinar kne knp +application/vnd.koan skp skd skt skm +application/vnd.kodak-descriptor sse +application/vnd.las.las+xml lasxml +# application/vnd.liberty-request+xml +application/vnd.llamagraphics.life-balance.desktop lbd +application/vnd.llamagraphics.life-balance.exchange+xml lbe +application/vnd.lotus-1-2-3 123 +application/vnd.lotus-approach apr +application/vnd.lotus-freelance pre +application/vnd.lotus-notes nsf +application/vnd.lotus-organizer org +application/vnd.lotus-screencam scm +application/vnd.lotus-wordpro lwp +application/vnd.macports.portpkg portpkg +# application/vnd.marlin.drm.actiontoken+xml +# application/vnd.marlin.drm.conftoken+xml +# application/vnd.marlin.drm.license+xml +# application/vnd.marlin.drm.mdcf +application/vnd.mcd mcd +application/vnd.medcalcdata mc1 +application/vnd.mediastation.cdkey cdkey +# application/vnd.meridian-slingshot +application/vnd.mfer mwf +application/vnd.mfmp mfm +application/vnd.micrografx.flo flo +application/vnd.micrografx.igx igx +application/vnd.mif mif +# application/vnd.minisoft-hp3000-save +# application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.mobius.daf daf +application/vnd.mobius.dis dis +application/vnd.mobius.mbk mbk +application/vnd.mobius.mqy mqy +application/vnd.mobius.msl msl +application/vnd.mobius.plc plc +application/vnd.mobius.txf txf +application/vnd.mophun.application mpn +application/vnd.mophun.certificate mpc +# application/vnd.motorola.flexsuite +# application/vnd.motorola.flexsuite.adsi +# application/vnd.motorola.flexsuite.fis +# application/vnd.motorola.flexsuite.gotap +# application/vnd.motorola.flexsuite.kmr +# application/vnd.motorola.flexsuite.ttc +# application/vnd.motorola.flexsuite.wem +# application/vnd.motorola.iprm +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry cil +# application/vnd.ms-asf +application/vnd.ms-cab-compressed cab +application/vnd.ms-excel xls xlm xla xlc xlt xlw +application/vnd.ms-excel.addin.macroenabled.12 xlam +application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb +application/vnd.ms-excel.sheet.macroenabled.12 xlsm +application/vnd.ms-excel.template.macroenabled.12 xltm +application/vnd.ms-fontobject eot +application/vnd.ms-htmlhelp chm +application/vnd.ms-ims ims +application/vnd.ms-lrm lrm +# application/vnd.ms-office.activex+xml +application/vnd.ms-officetheme thmx +application/vnd.ms-pki.seccat cat +application/vnd.ms-pki.stl stl +# application/vnd.ms-playready.initiator+xml +application/vnd.ms-powerpoint ppt pps pot +application/vnd.ms-powerpoint.addin.macroenabled.12 ppam +application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm +application/vnd.ms-powerpoint.slide.macroenabled.12 sldm +application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm +application/vnd.ms-powerpoint.template.macroenabled.12 potm +application/vnd.ms-project mpp mpt +# application/vnd.ms-tnef +# application/vnd.ms-wmdrm.lic-chlg-req +# application/vnd.ms-wmdrm.lic-resp +# application/vnd.ms-wmdrm.meter-chlg-req +# application/vnd.ms-wmdrm.meter-resp +application/vnd.ms-word.document.macroenabled.12 docm +application/vnd.ms-word.template.macroenabled.12 dotm +application/vnd.ms-works wps wks wcm wdb +application/vnd.ms-wpl wpl +application/vnd.ms-xpsdocument xps +application/vnd.mseq mseq +# application/vnd.msign +# application/vnd.multiad.creator +# application/vnd.multiad.creator.cif +# application/vnd.music-niff +application/vnd.musician mus +application/vnd.muvee.style msty +# application/vnd.ncd.control +# application/vnd.ncd.reference +# application/vnd.nervana +# application/vnd.netfpx +application/vnd.neurolanguage.nlu nlu +application/vnd.noblenet-directory nnd +application/vnd.noblenet-sealer nns +application/vnd.noblenet-web nnw +# application/vnd.nokia.catalogs +# application/vnd.nokia.conml+wbxml +# application/vnd.nokia.conml+xml +# application/vnd.nokia.isds-radio-presets +# application/vnd.nokia.iptv.config+xml +# application/vnd.nokia.landmark+wbxml +# application/vnd.nokia.landmark+xml +# application/vnd.nokia.landmarkcollection+xml +# application/vnd.nokia.n-gage.ac+xml +application/vnd.nokia.n-gage.data ngdat +application/vnd.nokia.n-gage.symbian.install n-gage +# application/vnd.nokia.ncd +# application/vnd.nokia.pcd+wbxml +# application/vnd.nokia.pcd+xml +application/vnd.nokia.radio-preset rpst +application/vnd.nokia.radio-presets rpss +application/vnd.novadigm.edm edm +application/vnd.novadigm.edx edx +application/vnd.novadigm.ext ext +# application/vnd.ntt-local.file-transfer +# application/vnd.ntt-local.sip-ta_remote +# application/vnd.ntt-local.sip-ta_tcp_stream +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.chart-template otc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.formula-template odft +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.image-template oti +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +# application/vnd.obn +# application/vnd.oipf.contentaccessdownload+xml +# application/vnd.oipf.contentaccessstreaming+xml +# application/vnd.oipf.cspg-hexbinary +# application/vnd.oipf.dae.svg+xml +# application/vnd.oipf.dae.xhtml+xml +# application/vnd.oipf.mippvcontrolmessage+xml +# application/vnd.oipf.pae.gem +# application/vnd.oipf.spdiscovery+xml +# application/vnd.oipf.spdlist+xml +# application/vnd.oipf.ueprofile+xml +# application/vnd.oipf.userprofile+xml +application/vnd.olpc-sugar xo +# application/vnd.oma-scws-config +# application/vnd.oma-scws-http-request +# application/vnd.oma-scws-http-response +# application/vnd.oma.bcast.associated-procedure-parameter+xml +# application/vnd.oma.bcast.drm-trigger+xml +# application/vnd.oma.bcast.imd+xml +# application/vnd.oma.bcast.ltkm +# application/vnd.oma.bcast.notification+xml +# application/vnd.oma.bcast.provisioningtrigger +# application/vnd.oma.bcast.sgboot +# application/vnd.oma.bcast.sgdd+xml +# application/vnd.oma.bcast.sgdu +# application/vnd.oma.bcast.simple-symbol-container +# application/vnd.oma.bcast.smartcard-trigger+xml +# application/vnd.oma.bcast.sprov+xml +# application/vnd.oma.bcast.stkm +# application/vnd.oma.cab-address-book+xml +# application/vnd.oma.cab-pcc+xml +# application/vnd.oma.dcd +# application/vnd.oma.dcdc +application/vnd.oma.dd2+xml dd2 +# application/vnd.oma.drm.risd+xml +# application/vnd.oma.group-usage-list+xml +# application/vnd.oma.poc.detailed-progress-report+xml +# application/vnd.oma.poc.final-report+xml +# application/vnd.oma.poc.groups+xml +# application/vnd.oma.poc.invocation-descriptor+xml +# application/vnd.oma.poc.optimized-progress-report+xml +# application/vnd.oma.push +# application/vnd.oma.scidm.messages+xml +# application/vnd.oma.xcap-directory+xml +# application/vnd.omads-email+xml +# application/vnd.omads-file+xml +# application/vnd.omads-folder+xml +# application/vnd.omaloc-supl-init +application/vnd.openofficeorg.extension oxt +# application/vnd.openxmlformats-officedocument.custom-properties+xml +# application/vnd.openxmlformats-officedocument.customxmlproperties+xml +# application/vnd.openxmlformats-officedocument.drawing+xml +# application/vnd.openxmlformats-officedocument.drawingml.chart+xml +# application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml +# application/vnd.openxmlformats-officedocument.extended-properties+xml +# application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml +# application/vnd.openxmlformats-officedocument.presentationml.comments+xml +# application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml +# application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml +# application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml +application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +# application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.presprops+xml +application/vnd.openxmlformats-officedocument.presentationml.slide sldx +# application/vnd.openxmlformats-officedocument.presentationml.slide+xml +# application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml +# application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml +application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx +# application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml +# application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml +# application/vnd.openxmlformats-officedocument.presentationml.tags+xml +application/vnd.openxmlformats-officedocument.presentationml.template potx +# application/vnd.openxmlformats-officedocument.presentationml.template.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +# application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx +# application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml +# application/vnd.openxmlformats-officedocument.theme+xml +# application/vnd.openxmlformats-officedocument.themeoverride+xml +# application/vnd.openxmlformats-officedocument.vmldrawing +# application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +# application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx +# application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml +# application/vnd.openxmlformats-package.core-properties+xml +# application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml +# application/vnd.openxmlformats-package.relationships+xml +# application/vnd.quobject-quoxdocument +# application/vnd.osa.netdeploy +application/vnd.osgeo.mapguide.package mgp +# application/vnd.osgi.bundle +application/vnd.osgi.dp dp +# application/vnd.otps.ct-kip+xml +application/vnd.palm pdb pqa oprc +# application/vnd.paos.xml +application/vnd.pawaafile paw +application/vnd.pg.format str +application/vnd.pg.osasli ei6 +# application/vnd.piaccess.application-licence +application/vnd.picsel efif +application/vnd.pmi.widget wg +# application/vnd.poc.group-advertisement+xml +application/vnd.pocketlearn plf +application/vnd.powerbuilder6 pbd +# application/vnd.powerbuilder6-s +# application/vnd.powerbuilder7 +# application/vnd.powerbuilder7-s +# application/vnd.powerbuilder75 +# application/vnd.powerbuilder75-s +# application/vnd.preminet +application/vnd.previewsystems.box box +application/vnd.proteus.magazine mgz +application/vnd.publishare-delta-tree qps +application/vnd.pvi.ptid1 ptid +# application/vnd.pwg-multiplexed +# application/vnd.pwg-xhtml-print+xml +# application/vnd.qualcomm.brew-app-res +application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb +# application/vnd.radisys.moml+xml +# application/vnd.radisys.msml+xml +# application/vnd.radisys.msml-audit+xml +# application/vnd.radisys.msml-audit-conf+xml +# application/vnd.radisys.msml-audit-conn+xml +# application/vnd.radisys.msml-audit-dialog+xml +# application/vnd.radisys.msml-audit-stream+xml +# application/vnd.radisys.msml-conf+xml +# application/vnd.radisys.msml-dialog+xml +# application/vnd.radisys.msml-dialog-base+xml +# application/vnd.radisys.msml-dialog-fax-detect+xml +# application/vnd.radisys.msml-dialog-fax-sendrecv+xml +# application/vnd.radisys.msml-dialog-group+xml +# application/vnd.radisys.msml-dialog-speech+xml +# application/vnd.radisys.msml-dialog-transform+xml +# application/vnd.rainstor.data +# application/vnd.rapid +application/vnd.realvnc.bed bed +application/vnd.recordare.musicxml mxl +application/vnd.recordare.musicxml+xml musicxml +# application/vnd.renlearn.rlprint +application/vnd.rig.cryptonote cryptonote +application/vnd.rim.cod cod +application/vnd.rn-realmedia rm +application/vnd.route66.link66+xml link66 +# application/vnd.ruckus.download +# application/vnd.s3sms +application/vnd.sailingtracker.track st +# application/vnd.sbm.cid +# application/vnd.sbm.mid2 +# application/vnd.scribus +# application/vnd.sealed.3df +# application/vnd.sealed.csf +# application/vnd.sealed.doc +# application/vnd.sealed.eml +# application/vnd.sealed.mht +# application/vnd.sealed.net +# application/vnd.sealed.ppt +# application/vnd.sealed.tiff +# application/vnd.sealed.xls +# application/vnd.sealedmedia.softseal.html +# application/vnd.sealedmedia.softseal.pdf +application/vnd.seemail see +application/vnd.sema sema +application/vnd.semd semd +application/vnd.semf semf +application/vnd.shana.informed.formdata ifm +application/vnd.shana.informed.formtemplate itp +application/vnd.shana.informed.interchange iif +application/vnd.shana.informed.package ipk +application/vnd.simtech-mindmapper twd twds +application/vnd.smaf mmf +# application/vnd.smart.notebook +application/vnd.smart.teacher teacher +# application/vnd.software602.filler.form+xml +# application/vnd.software602.filler.form-xml-zip +application/vnd.solent.sdkm+xml sdkm sdkd +application/vnd.spotfire.dxp dxp +application/vnd.spotfire.sfs sfs +# application/vnd.sss-cod +# application/vnd.sss-dtf +# application/vnd.sss-ntf +application/vnd.stardivision.calc sdc +application/vnd.stardivision.draw sda +application/vnd.stardivision.impress sdd +application/vnd.stardivision.math smf +application/vnd.stardivision.writer sdw vor +application/vnd.stardivision.writer-global sgl +application/vnd.stepmania.stepchart sm +# application/vnd.street-stream +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +# application/vnd.sun.wadl+xml +application/vnd.sus-calendar sus susp +application/vnd.svd svd +# application/vnd.swiftview-ics +application/vnd.symbian.install sis sisx +application/vnd.syncml+xml xsm +application/vnd.syncml.dm+wbxml bdm +application/vnd.syncml.dm+xml xdm +# application/vnd.syncml.dm.notification +# application/vnd.syncml.ds.notification +application/vnd.tao.intent-module-archive tao +application/vnd.tmobile-livetv tmo +application/vnd.trid.tpt tpt +application/vnd.triscape.mxs mxs +application/vnd.trueapp tra +# application/vnd.truedoc +# application/vnd.ubisoft.webplayer +application/vnd.ufdl ufd ufdl +application/vnd.uiq.theme utz +application/vnd.umajin umj +application/vnd.unity unityweb +application/vnd.uoml+xml uoml +# application/vnd.uplanet.alert +# application/vnd.uplanet.alert-wbxml +# application/vnd.uplanet.bearer-choice +# application/vnd.uplanet.bearer-choice-wbxml +# application/vnd.uplanet.cacheop +# application/vnd.uplanet.cacheop-wbxml +# application/vnd.uplanet.channel +# application/vnd.uplanet.channel-wbxml +# application/vnd.uplanet.list +# application/vnd.uplanet.list-wbxml +# application/vnd.uplanet.listcmd +# application/vnd.uplanet.listcmd-wbxml +# application/vnd.uplanet.signal +application/vnd.vcx vcx +# application/vnd.vd-study +# application/vnd.vectorworks +# application/vnd.verimatrix.vcas +# application/vnd.vidsoft.vidconference +application/vnd.visio vsd vst vss vsw +application/vnd.visionary vis +# application/vnd.vividence.scriptfile +application/vnd.vsf vsf +# application/vnd.wap.sic +# application/vnd.wap.slc +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo wtb +# application/vnd.wfa.wsc +# application/vnd.wmc +# application/vnd.wmf.bootstrap +# application/vnd.wolfram.mathematica +# application/vnd.wolfram.mathematica.package +application/vnd.wolfram.player nbp +application/vnd.wordperfect wpd +application/vnd.wqd wqd +# application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf stf +# application/vnd.wv.csp+wbxml +# application/vnd.wv.csp+xml +# application/vnd.wv.ssp+xml +application/vnd.xara xar +application/vnd.xfdl xfdl +# application/vnd.xfdl.webform +# application/vnd.xmi+xml +# application/vnd.xmpie.cpkg +# application/vnd.xmpie.dpkg +# application/vnd.xmpie.plan +# application/vnd.xmpie.ppkg +# application/vnd.xmpie.xlim +application/vnd.yamaha.hv-dic hvd +application/vnd.yamaha.hv-script hvs +application/vnd.yamaha.hv-voice hvp +application/vnd.yamaha.openscoreformat osf +application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg +# application/vnd.yamaha.remote-setup +application/vnd.yamaha.smaf-audio saf +application/vnd.yamaha.smaf-phrase spf +# application/vnd.yamaha.tunnel-udpencap +application/vnd.yellowriver-custom-menu cmp +application/vnd.zul zir zirz +application/vnd.zzazz.deck+xml zaz +application/voicexml+xml vxml +# application/vq-rtcpxr +# application/watcherinfo+xml +# application/whoispp-query +# application/whoispp-response +application/widget wgt +application/winhlp hlp +# application/wita +# application/wordperfect5.1 +application/wsdl+xml wsdl +application/wspolicy+xml wspolicy +application/x-7z-compressed 7z +application/x-abiword abw +application/x-ace-compressed ace +application/x-authorware-bin aab x32 u32 vox +application/x-authorware-map aam +application/x-authorware-seg aas +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-bzip bz +application/x-bzip2 bz2 boz +application/x-cdlink vcd +application/x-chat chat +application/x-chess-pgn pgn +# application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-debian-package deb udeb +application/x-director dir dcr dxr cst cct cxt w3d fgd swa +application/x-doom wad +application/x-dtbncx+xml ncx +application/x-dtbook+xml dtb +application/x-dtbresource+xml res +application/x-dvi dvi +application/x-font-bdf bdf +# application/x-font-dos +# application/x-font-framemaker +application/x-font-ghostscript gsf +# application/x-font-libgrx +application/x-font-linux-psf psf +application/x-font-otf otf +application/x-font-pcf pcf +application/x-font-snf snf +# application/x-font-speedo +# application/x-font-sunos-news +application/x-font-ttf ttf ttc +application/x-font-type1 pfa pfb pfm afm +application/x-font-woff woff +# application/x-font-vfont +application/x-futuresplash spl +application/x-gnumeric gnumeric +application/x-gtar gtar +# application/x-gzip +application/x-hdf hdf +application/x-java-jnlp-file jnlp +application/x-latex latex +application/x-mobipocket-ebook prc mobi +application/x-ms-application application +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-ms-xbap xbap +application/x-msaccess mdb +application/x-msbinder obd +application/x-mscardfile crd +application/x-msclip clp +application/x-msdownload exe dll com bat msi +application/x-msmediaview mvb m13 m14 +application/x-msmetafile wmf +application/x-msmoney mny +application/x-mspublisher pub +application/x-msschedule scd +application/x-msterminal trm +application/x-mswrite wri +application/x-netcdf nc cdf +application/x-pkcs12 p12 pfx +application/x-pkcs7-certificates p7b spc +application/x-pkcs7-certreqresp p7r +application/x-rar-compressed rar +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-silverlight-app xap +application/x-stuffit sit +application/x-stuffitx sitx +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-tex-tfm tfm +application/x-texinfo texinfo texi +application/x-ustar ustar +application/x-wais-source src +application/x-x509-ca-cert der crt +application/x-xfig fig +application/x-xpinstall xpi +# application/x400-bp +# application/xcap-att+xml +# application/xcap-caps+xml +application/xcap-diff+xml xdf +# application/xcap-el+xml +# application/xcap-error+xml +# application/xcap-ns+xml +# application/xcon-conference-info-diff+xml +# application/xcon-conference-info+xml +application/xenc+xml xenc +application/xhtml+xml xhtml xht +# application/xhtml-voice+xml +application/xml xml xsl +application/xml-dtd dtd +# application/xml-external-parsed-entity +# application/xmpp+xml +application/xop+xml xop +application/xslt+xml xslt +application/xspf+xml xspf +application/xv+xml mxml xhvml xvml xvm +application/yang yang +application/yin+xml yin +application/zip zip +# audio/1d-interleaved-parityfec +# audio/32kadpcm +# audio/3gpp +# audio/3gpp2 +# audio/ac3 +audio/adpcm adp +# audio/amr +# audio/amr-wb +# audio/amr-wb+ +# audio/asc +# audio/atrac-advanced-lossless +# audio/atrac-x +# audio/atrac3 +audio/basic au snd +# audio/bv16 +# audio/bv32 +# audio/clearmode +# audio/cn +# audio/dat12 +# audio/dls +# audio/dsr-es201108 +# audio/dsr-es202050 +# audio/dsr-es202211 +# audio/dsr-es202212 +# audio/dvi4 +# audio/eac3 +# audio/evrc +# audio/evrc-qcp +# audio/evrc0 +# audio/evrc1 +# audio/evrcb +# audio/evrcb0 +# audio/evrcb1 +# audio/evrcwb +# audio/evrcwb0 +# audio/evrcwb1 +# audio/example +# audio/g719 +# audio/g722 +# audio/g7221 +# audio/g723 +# audio/g726-16 +# audio/g726-24 +# audio/g726-32 +# audio/g726-40 +# audio/g728 +# audio/g729 +# audio/g7291 +# audio/g729d +# audio/g729e +# audio/gsm +# audio/gsm-efr +# audio/gsm-hr-08 +# audio/ilbc +# audio/l16 +# audio/l20 +# audio/l24 +# audio/l8 +# audio/lpc +audio/midi mid midi kar rmi +# audio/mobile-xmf +audio/mp4 mp4a +# audio/mp4a-latm +# audio/mpa +# audio/mpa-robust +audio/mpeg mpga mp2 mp2a mp3 m2a m3a +# audio/mpeg4-generic +audio/ogg oga ogg spx +# audio/parityfec +# audio/pcma +# audio/pcma-wb +# audio/pcmu-wb +# audio/pcmu +# audio/prs.sid +# audio/qcelp +# audio/red +# audio/rtp-enc-aescm128 +# audio/rtp-midi +# audio/rtx +# audio/smv +# audio/smv0 +# audio/smv-qcp +# audio/sp-midi +# audio/speex +# audio/t140c +# audio/t38 +# audio/telephone-event +# audio/tone +# audio/uemclip +# audio/ulpfec +# audio/vdvi +# audio/vmr-wb +# audio/vnd.3gpp.iufp +# audio/vnd.4sb +# audio/vnd.audiokoz +# audio/vnd.celp +# audio/vnd.cisco.nse +# audio/vnd.cmles.radio-events +# audio/vnd.cns.anp1 +# audio/vnd.cns.inf1 +audio/vnd.dece.audio uva uvva +audio/vnd.digital-winds eol +# audio/vnd.dlna.adts +# audio/vnd.dolby.heaac.1 +# audio/vnd.dolby.heaac.2 +# audio/vnd.dolby.mlp +# audio/vnd.dolby.mps +# audio/vnd.dolby.pl2 +# audio/vnd.dolby.pl2x +# audio/vnd.dolby.pl2z +# audio/vnd.dolby.pulse.1 +audio/vnd.dra dra +audio/vnd.dts dts +audio/vnd.dts.hd dtshd +# audio/vnd.everad.plj +# audio/vnd.hns.audio +audio/vnd.lucent.voice lvp +audio/vnd.ms-playready.media.pya pya +# audio/vnd.nokia.mobile-xmf +# audio/vnd.nortel.vbk +audio/vnd.nuera.ecelp4800 ecelp4800 +audio/vnd.nuera.ecelp7470 ecelp7470 +audio/vnd.nuera.ecelp9600 ecelp9600 +# audio/vnd.octel.sbc +# audio/vnd.qcelp +# audio/vnd.rhetorex.32kadpcm +audio/vnd.rip rip +# audio/vnd.sealedmedia.softseal.mpeg +# audio/vnd.vmx.cvsd +# audio/vorbis +# audio/vorbis-config +audio/webm weba +audio/x-aac aac +audio/x-aiff aif aiff aifc +audio/x-mpegurl m3u +audio/x-ms-wax wax +audio/x-ms-wma wma +audio/x-pn-realaudio ram ra +audio/x-pn-realaudio-plugin rmp +audio/x-wav wav +chemical/x-cdx cdx +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-csml csml +# chemical/x-pdb +chemical/x-xyz xyz +image/bmp bmp +image/cgm cgm +# image/example +# image/fits +image/g3fax g3 +image/gif gif +image/ief ief +# image/jp2 +image/jpeg jpeg jpg jpe +# image/jpm +# image/jpx +image/ktx ktx +# image/naplps +image/png png +image/prs.btif btif +# image/prs.pti +image/svg+xml svg svgz +# image/t38 +image/tiff tiff tif +# image/tiff-fx +image/vnd.adobe.photoshop psd +# image/vnd.cns.inf2 +image/vnd.dece.graphic uvi uvvi uvg uvvg +image/vnd.dvb.subtitle sub +image/vnd.djvu djvu djv +image/vnd.dwg dwg +image/vnd.dxf dxf +image/vnd.fastbidsheet fbs +image/vnd.fpx fpx +image/vnd.fst fst +image/vnd.fujixerox.edmics-mmr mmr +image/vnd.fujixerox.edmics-rlc rlc +# image/vnd.globalgraphics.pgb +# image/vnd.microsoft.icon +# image/vnd.mix +image/vnd.ms-modi mdi +image/vnd.net-fpx npx +# image/vnd.radiance +# image/vnd.sealed.png +# image/vnd.sealedmedia.softseal.gif +# image/vnd.sealedmedia.softseal.jpg +# image/vnd.svf +image/vnd.wap.wbmp wbmp +image/vnd.xiff xif +image/webp webp +image/x-cmu-raster ras +image/x-cmx cmx +image/x-freehand fh fhc fh4 fh5 fh7 +image/x-icon ico +image/x-pcx pcx +image/x-pict pic pct +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +# message/cpim +# message/delivery-status +# message/disposition-notification +# message/example +# message/external-body +# message/feedback-report +# message/global +# message/global-delivery-status +# message/global-disposition-notification +# message/global-headers +# message/http +# message/imdn+xml +# message/news +# message/partial +message/rfc822 eml mime +# message/s-http +# message/sip +# message/sipfrag +# message/tracking-status +# message/vnd.si.simp +# model/example +model/iges igs iges +model/mesh msh mesh silo +model/vnd.collada+xml dae +model/vnd.dwf dwf +# model/vnd.flatland.3dml +model/vnd.gdl gdl +# model/vnd.gs-gdl +# model/vnd.gs.gdl +model/vnd.gtw gtw +# model/vnd.moml+xml +model/vnd.mts mts +# model/vnd.parasolid.transmit.binary +# model/vnd.parasolid.transmit.text +model/vnd.vtu vtu +model/vrml wrl vrml +# multipart/alternative +# multipart/appledouble +# multipart/byteranges +# multipart/digest +# multipart/encrypted +# multipart/example +# multipart/form-data +# multipart/header-set +# multipart/mixed +# multipart/parallel +# multipart/related +# multipart/report +# multipart/signed +# multipart/voice-message +# text/1d-interleaved-parityfec +text/calendar ics ifb +text/css css +text/csv csv +# text/directory +# text/dns +# text/ecmascript +# text/enriched +# text/example +text/html html htm +# text/javascript +text/n3 n3 +# text/parityfec +text/plain txt text conf def list log in +# text/prs.fallenstein.rst +text/prs.lines.tag dsc +# text/vnd.radisys.msml-basic-layout +# text/red +# text/rfc822-headers +text/richtext rtx +# text/rtf +# text/rtp-enc-aescm128 +# text/rtx +text/sgml sgml sgm +# text/t140 +text/tab-separated-values tsv +text/troff t tr roff man me ms +text/turtle ttl +# text/ulpfec +text/uri-list uri uris urls +# text/vnd.abc +text/vnd.curl curl +text/vnd.curl.dcurl dcurl +text/vnd.curl.scurl scurl +text/vnd.curl.mcurl mcurl +# text/vnd.dmclientscript +# text/vnd.esmertec.theme-descriptor +text/vnd.fly fly +text/vnd.fmi.flexstor flx +text/vnd.graphviz gv +text/vnd.in3d.3dml 3dml +text/vnd.in3d.spot spot +# text/vnd.iptc.newsml +# text/vnd.iptc.nitf +# text/vnd.latex-z +# text/vnd.motorola.reflex +# text/vnd.ms-mediapackage +# text/vnd.net2phone.commcenter.command +# text/vnd.si.uricatalogue +text/vnd.sun.j2me.app-descriptor jad +# text/vnd.trolltech.linguist +# text/vnd.wap.si +# text/vnd.wap.sl +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-asm s asm +text/x-c c cc cxx cpp h hh dic +text/x-fortran f for f77 f90 +text/x-pascal p pas +text/x-java-source java +text/x-setext etx +text/x-uuencode uu +text/x-vcalendar vcs +text/x-vcard vcf +# text/xml +# text/xml-external-parsed-entity +# video/1d-interleaved-parityfec +video/3gpp 3gp +# video/3gpp-tt +video/3gpp2 3g2 +# video/bmpeg +# video/bt656 +# video/celb +# video/dv +# video/example +video/h261 h261 +video/h263 h263 +# video/h263-1998 +# video/h263-2000 +video/h264 h264 +# video/h264-rcdo +# video/h264-svc +video/jpeg jpgv +# video/jpeg2000 +video/jpm jpm jpgm +video/mj2 mj2 mjp2 +# video/mp1s +# video/mp2p +# video/mp2t +video/mp4 mp4 mp4v mpg4 +# video/mp4v-es +video/mpeg mpeg mpg mpe m1v m2v +# video/mpeg4-generic +# video/mpv +# video/nv +video/ogg ogv +# video/parityfec +# video/pointer +video/quicktime qt mov +# video/raw +# video/rtp-enc-aescm128 +# video/rtx +# video/smpte292m +# video/ulpfec +# video/vc1 +# video/vnd.cctv +video/vnd.dece.hd uvh uvvh +video/vnd.dece.mobile uvm uvvm +# video/vnd.dece.mp4 +video/vnd.dece.pd uvp uvvp +video/vnd.dece.sd uvs uvvs +video/vnd.dece.video uvv uvvv +# video/vnd.directv.mpeg +# video/vnd.directv.mpeg-tts +# video/vnd.dlna.mpeg-tts +video/vnd.fvt fvt +# video/vnd.hns.video +# video/vnd.iptvforum.1dparityfec-1010 +# video/vnd.iptvforum.1dparityfec-2005 +# video/vnd.iptvforum.2dparityfec-1010 +# video/vnd.iptvforum.2dparityfec-2005 +# video/vnd.iptvforum.ttsavc +# video/vnd.iptvforum.ttsmpeg2 +# video/vnd.motorola.video +# video/vnd.motorola.videop +video/vnd.mpegurl mxu m4u +video/vnd.ms-playready.media.pyv pyv +# video/vnd.nokia.interleaved-multimedia +# video/vnd.nokia.videovoip +# video/vnd.objectvideo +# video/vnd.sealed.mpeg1 +# video/vnd.sealed.mpeg4 +# video/vnd.sealed.swf +# video/vnd.sealedmedia.softseal.mov +video/vnd.uvvu.mp4 uvu uvvu +video/vnd.vivo viv +video/webm webm +video/x-f4v f4v +video/x-fli fli +video/x-flv flv +video/x-m4v m4v +video/x-ms-asf asf asx +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +x-conference/x-cooltalk ice