| 1 |
User visible changes in Foolscap (aka newpb/pb2). -*- outline -*- |
|---|
| 2 |
|
|---|
| 3 |
* Release 0.3.2 (14 Oct 2008) |
|---|
| 4 |
|
|---|
| 5 |
** Compatibility: same as 0.2.6 |
|---|
| 6 |
|
|---|
| 7 |
Incident classifier functions (introduced in 0.3.0) have been changed: if you |
|---|
| 8 |
have written custom functions for an Incident Gatherer, you will need to |
|---|
| 9 |
modify them upon upgrading to this release. |
|---|
| 10 |
|
|---|
| 11 |
** Logging Changes |
|---|
| 12 |
|
|---|
| 13 |
The log.msg counter now uses a regular Python integer/bigint. The counter in |
|---|
| 14 |
0.3.1 used itertools.count(), which, despite its documentation, stores the |
|---|
| 15 |
counter in a C signed int, and thus throws an exception when the message |
|---|
| 16 |
number exceeds 2**31-1 . This exception would pretty much kill any program |
|---|
| 17 |
which ran long enough to emit this many messages, a situation which was |
|---|
| 18 |
observed in a busy production server with an uptime of about three or four |
|---|
| 19 |
weeks. The 0.3.2 counter will be promoted to a bigint when necessary, |
|---|
| 20 |
removing this limitation. (ticket #99) |
|---|
| 21 |
|
|---|
| 22 |
The Incident-Gatherer now imports classification functions from files named |
|---|
| 23 |
'classify_*.py' in the gatherer's directory. This effectively adds |
|---|
| 24 |
"classifier plugins". The signature of the functions has changed since the |
|---|
| 25 |
0.3.0 release, making them easier to use. If you have written custom |
|---|
| 26 |
functions (and edited the gatherer.tac file to activate them, using |
|---|
| 27 |
gs.add_classifier()), you will need to modify the functions to take a single |
|---|
| 28 |
'trigger' argument. |
|---|
| 29 |
|
|---|
| 30 |
These same 'classify_*.py' plugins are used by a new "flogtool |
|---|
| 31 |
classify-incident" subcommand, which can be pointed at an incident file, and |
|---|
| 32 |
performs the same kind of classification as the Incident Gatherer. (#102). |
|---|
| 33 |
|
|---|
| 34 |
The logfiles produced by the "flogtool tail" command and the internal |
|---|
| 35 |
incident-reporter now include the PID of the reporting process. This can be |
|---|
| 36 |
seen by passing the --verbose option to "flogtool dump", and will be made |
|---|
| 37 |
more visible in later releases. (#80). |
|---|
| 38 |
|
|---|
| 39 |
The "flogtool web-viewer" tool now marks Incident triggers (#79), and |
|---|
| 40 |
features a "Reload Logfile" button to re-read the logfile on disk (#103). |
|---|
| 41 |
This is most useful when running unit tests, in conjunction with the |
|---|
| 42 |
FLOGFILE= environment variable. |
|---|
| 43 |
|
|---|
| 44 |
** Other Changes |
|---|
| 45 |
|
|---|
| 46 |
When running unit tests, if the #62 bug is encountered (pyopenssl >= 0.7 and |
|---|
| 47 |
twisted <= 8.1.0 and selectreactor), the test process will emit a warning and |
|---|
| 48 |
pause for ten seconds to give the operator a chance to halt the test and |
|---|
| 49 |
re-run it with --reactor=poll. This may help to reduce the confusion of a |
|---|
| 50 |
hanging+failing test run. |
|---|
| 51 |
|
|---|
| 52 |
The xfer-client.py example tool (in doc/listings/) has been made more |
|---|
| 53 |
useable, by calling os.path.expanduser() on its input files, and by doing |
|---|
| 54 |
sys.exit(1) on failure (instead of hanging), so that external programs can |
|---|
| 55 |
react appropriately. |
|---|
| 56 |
|
|---|
| 57 |
|
|---|
| 58 |
* Release 0.3.1 (03 Sep 2008) |
|---|
| 59 |
|
|---|
| 60 |
** Compatibility: same as 0.2.6 |
|---|
| 61 |
|
|---|
| 62 |
** callRemote API changes: DeadReferenceError |
|---|
| 63 |
|
|---|
| 64 |
All partitioning exceptions are now mapped to DeadReferenceError. Previously |
|---|
| 65 |
there were three separate exceptions that might indicate a network partition: |
|---|
| 66 |
DeadReferenceError, ConnectionLost, and ConnectionDone. (a network partition |
|---|
| 67 |
is when one party cannot reach the other party, due to a variety of reasons: |
|---|
| 68 |
temporary network failure, the remote program being shut down, the remote |
|---|
| 69 |
host being taken offline, etc). |
|---|
| 70 |
|
|---|
| 71 |
This means that, if you want to send a message and don't care whether that |
|---|
| 72 |
message makes it to the recipient or not (but you *do* still care if the |
|---|
| 73 |
recipient raises an exception during processing of that message), you can set |
|---|
| 74 |
up the Deferred chain like this: |
|---|
| 75 |
|
|---|
| 76 |
d = rref.callRemote("message", args) |
|---|
| 77 |
d.addCallback(self.handle_response) |
|---|
| 78 |
d.addErrback(lambda f: f.trap(foolscap.DeadReferenceError)) |
|---|
| 79 |
d.addErrback(log.err) |
|---|
| 80 |
|
|---|
| 81 |
The first d.addErrback will use f.trap to catch DeadReferenceError, but will |
|---|
| 82 |
pass other exceptions through to the log.err() errback. This will cause |
|---|
| 83 |
DeadReferenceError to be ignored, but other errors to be logged. |
|---|
| 84 |
|
|---|
| 85 |
DeadReferenceError will be signalled in any of the following situations: |
|---|
| 86 |
|
|---|
| 87 |
1: the TCP connection was lost before callRemote was invoked |
|---|
| 88 |
2: the connection was lost after the request was sent, but before |
|---|
| 89 |
the response was received |
|---|
| 90 |
3: when the active connection is dropped because a duplicate connection was |
|---|
| 91 |
established. This can occur when two programs are simultaneously |
|---|
| 92 |
connecting to each other. |
|---|
| 93 |
|
|---|
| 94 |
** logging improvements |
|---|
| 95 |
|
|---|
| 96 |
*** bridge foolscap logs into twistd.log |
|---|
| 97 |
|
|---|
| 98 |
By calling foolscap.logging.log.bridgeLogsToTwisted(), or by setting the |
|---|
| 99 |
$FLOGTOTWISTED environment variable (to anything), a subset of Foolscap log |
|---|
| 100 |
events will be copied into the Twisted logging system. The default filter |
|---|
| 101 |
will not copy events below the log.OPERATIONAL level, nor will it copy |
|---|
| 102 |
internal foolscap events (i.e. those with a facility name that starts with |
|---|
| 103 |
"foolscap"). This mechanism is careful to avoid loops, so it is safe to use |
|---|
| 104 |
both bridgeLogsToTwisted() and bridgeTwistedLogs() at the same time. The |
|---|
| 105 |
events that are copied into the Twisted logging system will typically show up |
|---|
| 106 |
in the twistd.log file (for applications that are run under twistd). |
|---|
| 107 |
|
|---|
| 108 |
An alternate filter function can be passed to bridgeLogsToTwisted(). |
|---|
| 109 |
|
|---|
| 110 |
This feature provides a human-readable on-disk record of significant events, |
|---|
| 111 |
using a traditional one-line-per-event all-text sequential logging structure. |
|---|
| 112 |
It does not record parent/child relationships, structured event data, or |
|---|
| 113 |
causality information. |
|---|
| 114 |
|
|---|
| 115 |
*** Incident Gatherer improvements |
|---|
| 116 |
|
|---|
| 117 |
If an Incident occurs while a previous Incident is still being recorded (i.e. |
|---|
| 118 |
during the "trailing log period"), the two will be folded together. |
|---|
| 119 |
Specifically, the second event will not trigger a new Incident, but will be |
|---|
| 120 |
recorded in the first Incident as a normal log event. This serves to address |
|---|
| 121 |
some performance problems we've seen when incident triggers occur in |
|---|
| 122 |
clusters, which used to cause dozens of simultaneous Incident Recorders to |
|---|
| 123 |
swing into action. |
|---|
| 124 |
|
|---|
| 125 |
The Incident Gatherer has been changed to only fetch one Incident at a time |
|---|
| 126 |
(per publishing application), to avoid overloading the app with a large |
|---|
| 127 |
outbound TCP queue. |
|---|
| 128 |
|
|---|
| 129 |
The Incident Gatherer has also been changed to scan the classified/* output |
|---|
| 130 |
files and reclassify any stored incidents it has that are not mentioned in |
|---|
| 131 |
one of these files. This means that you can update the classification |
|---|
| 132 |
functions (to add a function for some previously unknown type of incident), |
|---|
| 133 |
delete the classified/unknown file, then restart the incident gatherer, and |
|---|
| 134 |
it will only reclassify the previously-unknown incidents. This makes it much |
|---|
| 135 |
easier to iteratively develop classification functions. |
|---|
| 136 |
|
|---|
| 137 |
*** Application Version data |
|---|
| 138 |
|
|---|
| 139 |
The table of application versions, previously displayed only by the 'flogtool |
|---|
| 140 |
tail' command, is now recorded in the header of both Incidents and the |
|---|
| 141 |
'flogtool tail --save-to' output file. |
|---|
| 142 |
|
|---|
| 143 |
The API to add application versions has changed: now programs should call |
|---|
| 144 |
foolscap.logging.app_versions.add_version(name, verstr). |
|---|
| 145 |
|
|---|
| 146 |
|
|---|
| 147 |
* Release 0.3.0 (04 Aug 2008) |
|---|
| 148 |
|
|---|
| 149 |
** Compatibility: same as 0.2.6 |
|---|
| 150 |
|
|---|
| 151 |
The wire-level protocol remains the same as other recent releases. |
|---|
| 152 |
|
|---|
| 153 |
The new incident-gatherer will only work with applications that use Foolscap |
|---|
| 154 |
0.3.0 or later. |
|---|
| 155 |
|
|---|
| 156 |
** logging improvements |
|---|
| 157 |
|
|---|
| 158 |
The "incident gatherer" has finally been implemented. This is a service, like |
|---|
| 159 |
the log-gatherer, which subscribes to an application's logport and collects |
|---|
| 160 |
incident reports: each is a dump of accumulated log messages, triggered by |
|---|
| 161 |
some special event (such as those above a certain severity threshold). The |
|---|
| 162 |
"flogtool create-incident-gatherer" command is used to create one, and twistd |
|---|
| 163 |
is used to start it. Please see doc/logging.xhtml for more details. |
|---|
| 164 |
|
|---|
| 165 |
The incident publishing API was changed to support the incident-gatherer. The |
|---|
| 166 |
incident-gatherer will only work with logports using foolscap 0.3.0 or newer. |
|---|
| 167 |
|
|---|
| 168 |
The log-publishing API was changed slightly, to encourage the use of |
|---|
| 169 |
subscription.unsubscribe() rather than publisher.unsubscribe(subscription). |
|---|
| 170 |
The old API remains in place for backwards compatibility with log-gatherers |
|---|
| 171 |
running foolscap 0.2.9 or earlier. |
|---|
| 172 |
|
|---|
| 173 |
The Tub.setOption("log-gatherer-furlfile") can accept a file with multiple |
|---|
| 174 |
FURLs, one per line, instead of just a single FURL. This makes the |
|---|
| 175 |
application contact multiple log gatherers, offering its logport to each |
|---|
| 176 |
independently, e.g. to connect to both a log-gatherer and an |
|---|
| 177 |
incident-gatherer. |
|---|
| 178 |
|
|---|
| 179 |
** API Additions |
|---|
| 180 |
|
|---|
| 181 |
RemoteReferences now have a getRemoteTubID() method, which returns a string |
|---|
| 182 |
(base32-encoded) representing the secure Tub ID of the remote end of the |
|---|
| 183 |
connection. For any given Tub ID, only the possessor of the matching private |
|---|
| 184 |
key should be able to provide a RemoteReference for which getRemoteTubID() |
|---|
| 185 |
will return that value. I'm not yet sure if getRemoteTubID() is a good idea |
|---|
| 186 |
or not (the traditional object-capability model discourages making |
|---|
| 187 |
access-control decisions on the basis of "who", instead these decisions |
|---|
| 188 |
should be controlled by "what": what objects do they have access to). This |
|---|
| 189 |
method is intended for use by application code that needs to use TubIDs as an |
|---|
| 190 |
index into a table of some sort. It is used by Tahoe to securely compute |
|---|
| 191 |
shared cryptographic secrets for each remote server (by hashing the TubID |
|---|
| 192 |
together with some other string). |
|---|
| 193 |
|
|---|
| 194 |
Note that the rref.getSturdyRef() call (which has been present in Foolscap |
|---|
| 195 |
since forever) is *not* secure: the remote application controls all parts of |
|---|
| 196 |
the sturdy ref FURL, including the tubid. A future version of foolscap may |
|---|
| 197 |
remedy this. |
|---|
| 198 |
|
|---|
| 199 |
** Bug fixes |
|---|
| 200 |
|
|---|
| 201 |
The log-gatherer FURL can now be set before Tub.setLocation (the connection |
|---|
| 202 |
request will be deferred until setLocation is called), and |
|---|
| 203 |
getLogPort/getLogPortFURL cannot be called until after setLocation. These two |
|---|
| 204 |
changes, in combination, resolve a problem (#55) in which the gatherer |
|---|
| 205 |
connection could be made before the logport was ready, causing the |
|---|
| 206 |
log-gatherer to fail to subscribe to receive log events. |
|---|
| 207 |
|
|---|
| 208 |
** Dependent Libraries |
|---|
| 209 |
|
|---|
| 210 |
Foolscap uses PyOpenSSL for all of its cryptographic routines. A bug (#62) |
|---|
| 211 |
has been found in which the current version of Twisted (8.1.0) and the |
|---|
| 212 |
current version of PyOpenSSL (0.7) interact badly, causing Foolscap's unit |
|---|
| 213 |
tests to fail. This problem will affect application code as well |
|---|
| 214 |
(specifically, Tub.stopService will hang forever). The problem only appears |
|---|
| 215 |
to affect the selectreactor, so the current recommended workaround is to run |
|---|
| 216 |
unit tests (and applications that need to shut down Tubs) with --reactor=poll |
|---|
| 217 |
(or whatever other reactor is appropriate for the platform, perhaps iocp). A |
|---|
| 218 |
less-desireable workaround is to downgrade PyOpenSSL to 0.6, or Twisted to |
|---|
| 219 |
something older. The Twisted maintainers are aware of the problem and intend |
|---|
| 220 |
to fix it in an upcoming Twisted release. |
|---|
| 221 |
|
|---|
| 222 |
|
|---|
| 223 |
* Release 0.2.9 (02 Jul 2008) |
|---|
| 224 |
|
|---|
| 225 |
** Compatibility: exactly the same as 0.2.6 |
|---|
| 226 |
|
|---|
| 227 |
** logging bugs fixed |
|---|
| 228 |
|
|---|
| 229 |
The foolscap.logging.log.setLogDir() option would throw an exception if the |
|---|
| 230 |
directory already existed, making it unsuitable for use in an application |
|---|
| 231 |
which is expected to be run multiple times. This has been fixed. |
|---|
| 232 |
|
|---|
| 233 |
** logging improvements |
|---|
| 234 |
|
|---|
| 235 |
'flogtool tail' now displays the process ID and version information about the |
|---|
| 236 |
remote process. The tool will tolerate older versions of foolscap which do |
|---|
| 237 |
not offer the get_pid interface. (foolscap ticket #71) |
|---|
| 238 |
|
|---|
| 239 |
The remote logport now uses a size-limited queue for messages going to a |
|---|
| 240 |
gatherer or 'flogtool tail', to prevent the monitored process from using |
|---|
| 241 |
unbounded amounts of memory during overload situations (when it is generating |
|---|
| 242 |
messages faster than the receiver can handle them). This solves a runaway |
|---|
| 243 |
load problem we've seen in Tahoe production systems, in which a busy node |
|---|
| 244 |
sends log messages to a gatherer too quickly for it to absorb, using lots of |
|---|
| 245 |
memory to hold the pending messages, which causes swapping, which causes more |
|---|
| 246 |
load, making the problem worse. We frequently see an otherwise well-behaved |
|---|
| 247 |
process swell to 1.4GB due to this problem, occasionally failing due to VM |
|---|
| 248 |
exhaustion. Of course, a bounded queue means that new log events will be |
|---|
| 249 |
dropped during this overload situation. (#72) |
|---|
| 250 |
|
|---|
| 251 |
** serialization added for the Decimal type (#50) |
|---|
| 252 |
|
|---|
| 253 |
** debian packaging targets added for gutsy and hardy |
|---|
| 254 |
|
|---|
| 255 |
The Makefile now has 'make debian-gutsy' and 'make debian-hardy' targets. |
|---|
| 256 |
These do the same thing as 'make debian-feisty'. (#76) |
|---|
| 257 |
|
|---|
| 258 |
|
|---|
| 259 |
* Release 0.2.8 (04 Jun 2008) |
|---|
| 260 |
|
|---|
| 261 |
** Compatibility: exactly the same as 0.2.6 |
|---|
| 262 |
|
|---|
| 263 |
** setuptools dependencies updated |
|---|
| 264 |
|
|---|
| 265 |
Foolscap (when built with setuptools) now uses the "extras_require" feature |
|---|
| 266 |
to declare that it needs pyOpenSSL if you want to use the |
|---|
| 267 |
"secure_connections" feature. This makes easy_install easier to use in |
|---|
| 268 |
projects that depend upon Foolscap (and also insist upon using secure |
|---|
| 269 |
connections): they do not need to declare a dependency on pyOpenSSL |
|---|
| 270 |
themselves, instead they declare a dependency on |
|---|
| 271 |
"Foolscap[secure_connections]". See the following documentation for more |
|---|
| 272 |
details: |
|---|
| 273 |
http://peak.telecommunity.com/DevCenter/setuptools#declaring-extras-optional-features-with-their-own-dependencies |
|---|
| 274 |
|
|---|
| 275 |
** New RemoteReference.getPeer() method |
|---|
| 276 |
|
|---|
| 277 |
The new rref.getPeer() method will return address information about the far |
|---|
| 278 |
end of the connection, allowing you to determine their IP address and port |
|---|
| 279 |
number. This may be useful for debugging or diagnostic purposes. |
|---|
| 280 |
|
|---|
| 281 |
** Minor bugs fixed |
|---|
| 282 |
|
|---|
| 283 |
Tub.registerReference() with both name= and furlFile= arguments now works |
|---|
| 284 |
even when the furlFile= already exists. |
|---|
| 285 |
|
|---|
| 286 |
Tubs which have been shutdown now give more useful error messages when you |
|---|
| 287 |
(incorrectly) try to use them again. Previously a bug caused them to emit a |
|---|
| 288 |
TypeError. |
|---|
| 289 |
|
|---|
| 290 |
|
|---|
| 291 |
* Release 0.2.7 (13 May 2008) |
|---|
| 292 |
|
|---|
| 293 |
** Compatibility: exactly the same as 0.2.6 |
|---|
| 294 |
|
|---|
| 295 |
** flogtool works again |
|---|
| 296 |
|
|---|
| 297 |
The "flogtool" utility was completely non-functional in 0.2.6 . This has been |
|---|
| 298 |
fixed. |
|---|
| 299 |
|
|---|
| 300 |
** Known Issues |
|---|
| 301 |
|
|---|
| 302 |
*** some debian packages are wrong |
|---|
| 303 |
|
|---|
| 304 |
When using the 'make debian-dapper' target (to build a .deb for a dapper |
|---|
| 305 |
system), the resulting .deb sometimes includes a full copy of Twisted, and is |
|---|
| 306 |
probably unsuitable for installation. This appears to be a result of |
|---|
| 307 |
installation behavior changing due to setuptools being imported (even though |
|---|
| 308 |
it is not explicitly used). No other platforms .deb files seem to be affected |
|---|
| 309 |
this way. Package builders are advised to examine the generated .deb closely |
|---|
| 310 |
before using it. |
|---|
| 311 |
|
|---|
| 312 |
|
|---|
| 313 |
* Release 0.2.6 (06 May 2008) |
|---|
| 314 |
|
|---|
| 315 |
** Compatibility |
|---|
| 316 |
|
|---|
| 317 |
All releases between 0.1.3 and 0.2.6 (inclusive) are fully wire-compatible. |
|---|
| 318 |
|
|---|
| 319 |
The saved logfiles produced (by e.g. 'flogtool tail --save-to' and the |
|---|
| 320 |
log-gatherer) in 0.2.6 and beyond are not readable by tools (e.g. 'flogtool |
|---|
| 321 |
dump' and 'flogtool filter') from 0.2.5 and earlier. |
|---|
| 322 |
|
|---|
| 323 |
FURLs which contain "extensions" (described below) will not be tolerated by |
|---|
| 324 |
foolscap 0.2.5 or earlier. If, at some point in the future, we add such |
|---|
| 325 |
extensions to published FURLs, then such an application will require |
|---|
| 326 |
foolscap-0.2.6 or later to interpret those FURLs. |
|---|
| 327 |
|
|---|
| 328 |
** Logging Changes |
|---|
| 329 |
|
|---|
| 330 |
*** "Incident" Logging |
|---|
| 331 |
|
|---|
| 332 |
This release finally implements the "strangeness-triggered logging" espoused |
|---|
| 333 |
in doc/logging.xhtml . By giving the foolscap logging code a directory to |
|---|
| 334 |
work with, the logging system will automatically save a compressed pickled |
|---|
| 335 |
logfile containing the messages that lead up to sufficiently-severe log |
|---|
| 336 |
event. The docs explain how to control what "sufficiently-severe" means. |
|---|
| 337 |
These events are retrievable through the logport, although no tools have been |
|---|
| 338 |
written yet to actually extract them. They are also retrievable by using |
|---|
| 339 |
'flogtool dump' directly on the incident files. |
|---|
| 340 |
|
|---|
| 341 |
*** 'flogtool as a subcommand |
|---|
| 342 |
|
|---|
| 343 |
The implementation of the 'flogtool' executable has been rearranged to make |
|---|
| 344 |
it possible to add a 'flogtool' subcommand to some other executable. |
|---|
| 345 |
|
|---|
| 346 |
*** 'flogtool filter' now has --above LEVEL and --from TUBID options |
|---|
| 347 |
*** 'flogtool dump' has --rx-time option, also shows failure tracebacks |
|---|
| 348 |
*** gatherer: don't add erroneous UTC-implying "Z" suffix to filename timestamps |
|---|
| 349 |
*** 'flogtool tail': don't add spurious "0" to timestamps |
|---|
| 350 |
|
|---|
| 351 |
** constraints no longer reject ('reference',) sequences |
|---|
| 352 |
|
|---|
| 353 |
The foolscap/banana serialization protocol responds to sending two separate |
|---|
| 354 |
copies of the same object in the same callRemote message by emitting one |
|---|
| 355 |
serialized object sequence and one 'reference' sequence: this is the standard |
|---|
| 356 |
way by which cycles are broken in the serialized data. Unfortunately, the |
|---|
| 357 |
wire-level constraint checkers in 0.2.5 and earlier would reject reference |
|---|
| 358 |
sequences with a Violation exception: if they were expecting a tuple, they |
|---|
| 359 |
would reject anything else, even a reference sequence that pointed at a |
|---|
| 360 |
tuple. |
|---|
| 361 |
|
|---|
| 362 |
Worse yet, python's normal constant-object folding code can produce shared |
|---|
| 363 |
references where you might not expect. In the following example, the two |
|---|
| 364 |
tuples are identical objects (and result in a 'reference' sequence on the |
|---|
| 365 |
wire), despite the programmer having typed them separately: |
|---|
| 366 |
|
|---|
| 367 |
rref.callRemote("haveTwoTuples", (0,1), (0,1) ) |
|---|
| 368 |
|
|---|
| 369 |
Foolscap-0.2.6 now allows reference sequence in all wire-level constraint |
|---|
| 370 |
checks, to avoid this false-negative Violation. The post-deserialization |
|---|
| 371 |
check will still enforce the constraint properly. It just does it late enough |
|---|
| 372 |
to be able to tell what the reference points to. |
|---|
| 373 |
|
|---|
| 374 |
** Twisted/pyopenssl compatibility |
|---|
| 375 |
|
|---|
| 376 |
*** compatible with Twisted-8.0.x |
|---|
| 377 |
|
|---|
| 378 |
Some unit test failures under Twisted-8.0.x (the most recent release) were |
|---|
| 379 |
fixed: tests now pass against Twisted-8.0.x, and a buildbot is used to make |
|---|
| 380 |
sure compatibility is maintained in the future. |
|---|
| 381 |
|
|---|
| 382 |
*** incompatible with pyOpenSSL-0.7 |
|---|
| 383 |
|
|---|
| 384 |
An incompatibility has been discovered with the most recent version of |
|---|
| 385 |
PyOpenSSL. pyopenssl 0.6 works correctly, but pyopenssl 0.7 causes modern |
|---|
| 386 |
versions of Twisted (both 2.5.x and 8.0.x) to follow a code path that breaks |
|---|
| 387 |
the Foolscap unit tests. This may or may not cause a problem in actual |
|---|
| 388 |
application use (the symptom is that the non-winning parallel connections are |
|---|
| 389 |
not disconnected properly, and several negotiation timers are left running). |
|---|
| 390 |
Until a fix is developed for either Twisted or PyOpenSSL, the recommended |
|---|
| 391 |
workaround is to downgrade to PyOpenSSL-0.6 . Twisted bug #3218 and Foolscap |
|---|
| 392 |
bug #62 exist to track this problem. |
|---|
| 393 |
|
|---|
| 394 |
** setup.py is more setuptools-friendly |
|---|
| 395 |
|
|---|
| 396 |
The foolscap version string is located with a regular expression rather than |
|---|
| 397 |
an import, allowing setuptools to install Foolscap as a build-dependency of |
|---|
| 398 |
some other project without having Twisted available first. If setuptools is |
|---|
| 399 |
available, we also declare a dependency upon Twisted (at least 2.4.0), to |
|---|
| 400 |
give more information to the setuptools dependency-auto-installer. |
|---|
| 401 |
|
|---|
| 402 |
** Unauthenticated FURLs can now contain multiple connection hints |
|---|
| 403 |
|
|---|
| 404 |
Previously they were limited to a single one |
|---|
| 405 |
|
|---|
| 406 |
** FURLs can now contain extensions, providing forwards-compatibility |
|---|
| 407 |
|
|---|
| 408 |
The parsing of FURLs has been refined to tolerate (and ignore) certain kinds |
|---|
| 409 |
of extensions. The "tubid" section will be able to have additional |
|---|
| 410 |
identifiers (perhaps stronger hashes for the public key, or an |
|---|
| 411 |
encryption-ready EC-DSA public key). In addition, the "connection hints" |
|---|
| 412 |
section will be able to contain alternate protocol specifiers (for TCP over |
|---|
| 413 |
IPv6, or a less connection-oriented UDP transport). |
|---|
| 414 |
|
|---|
| 415 |
By ignoring such extensions, foolscap-0.2.6 will tolerate FURLs produced |
|---|
| 416 |
(with extensions) by some future version of foolscap. This marks the |
|---|
| 417 |
beginning of a "transition period": when such extensions are introduced, |
|---|
| 418 |
0.2.6 will be the oldest version still capable of interoperating with the |
|---|
| 419 |
extension-using new version. |
|---|
| 420 |
|
|---|
| 421 |
|
|---|
| 422 |
* Release 0.2.5 (25 Mar 2008) |
|---|
| 423 |
|
|---|
| 424 |
** Compatibility |
|---|
| 425 |
|
|---|
| 426 |
All releases between 0.1.3 and 0.2.5 (inclusive) are fully wire-compatible. |
|---|
| 427 |
|
|---|
| 428 |
The new 'flogtool tail --catch-up' command requires a log publisher running |
|---|
| 429 |
0.2.5 or later. 'flogtool tail' without the --catch-up option will work with |
|---|
| 430 |
earlier publishers. |
|---|
| 431 |
|
|---|
| 432 |
** Licensing clarification |
|---|
| 433 |
|
|---|
| 434 |
Foolscap is distributed under the (very liberal) terms of the MIT license, |
|---|
| 435 |
which is the same license that Twisted uses. It's been like this since the |
|---|
| 436 |
beginning, but this is the first release to make this obvious by including a |
|---|
| 437 |
LICENSE file. |
|---|
| 438 |
|
|---|
| 439 |
** foolscap.logging Changes |
|---|
| 440 |
|
|---|
| 441 |
'flogtool tail' now has a --catch-up option, which prompts the remote |
|---|
| 442 |
publisher to deliver stored historical events to the subscribe, in proper |
|---|
| 443 |
sequential order. This allows you to connect to a process that has just done |
|---|
| 444 |
something interesting and grab a copy of the log events relevant to that |
|---|
| 445 |
event. |
|---|
| 446 |
|
|---|
| 447 |
'flogtool tail' also has a --save-to option, which specifies a filename to |
|---|
| 448 |
which all captured events should be saved. This file can be processed further |
|---|
| 449 |
with 'flogtool dump', 'flogtool filter', or 'flogtool web-viewer'. This |
|---|
| 450 |
behaves much like the unix 'tee' utility, except that the saved data is |
|---|
| 451 |
recorded in a lossless binary format (whereas the text emitted to stdout is |
|---|
| 452 |
not particularly machine-readable). |
|---|
| 453 |
|
|---|
| 454 |
'flogtool tail' and 'flogtool dump' both emit human-readable log messages by |
|---|
| 455 |
default. The --verbose option will emit raw event dictionaries, which contain |
|---|
| 456 |
slightly more information but are harder to read. |
|---|
| 457 |
|
|---|
| 458 |
'flogtool create-gatherer' will create a log gatherer .tac file in a new |
|---|
| 459 |
working directory. This .tac file can be launched with 'twistd', the standard |
|---|
| 460 |
Twisted daemon-launching program. This is significantly easier to work with |
|---|
| 461 |
than the previous 'flogtool gather' command (which has been removed). The new |
|---|
| 462 |
--rotate option will cause the log-gatherer to switch to a new output file |
|---|
| 463 |
every N seconds. The --bzip option will make it compress the logfiles after |
|---|
| 464 |
rotating them. For example, a log gatherer that rotates and compresses log |
|---|
| 465 |
files once per day could be created and launched with: |
|---|
| 466 |
|
|---|
| 467 |
flogtool create-gatherer --rotate 86400 --bzip ./workdir |
|---|
| 468 |
(cd workdir && twistd -y gatherer.tac) |
|---|
| 469 |
|
|---|
| 470 |
** New sample programs |
|---|
| 471 |
|
|---|
| 472 |
doc/listings/command-server.py and command-client.py are a pair of programs |
|---|
| 473 |
that let you safely grant access to a specific command. The server is |
|---|
| 474 |
configured with a command line to run, and a directory to run it from. The |
|---|
| 475 |
client gets a FURL: when the client is executed, the server will run its |
|---|
| 476 |
preconfigured command. The client gets to see stdout and stderr (and the exit |
|---|
| 477 |
status), but does not get to influence the command being run in any way. |
|---|
| 478 |
This is much like setting up an ssh server with a restricted command, but |
|---|
| 479 |
somewhat easier to configure. |
|---|
| 480 |
|
|---|
| 481 |
doc/listings/xfer-server.py and xfer-client.py are similar, but provide file |
|---|
| 482 |
transfer services instead of command execution. |
|---|
| 483 |
|
|---|
| 484 |
** New Features |
|---|
| 485 |
|
|---|
| 486 |
Tub.setLocationAutomatically() will try to determine an externally-visible IP |
|---|
| 487 |
address and feed it to Tub.setLocation(). It does this by preparing to send a |
|---|
| 488 |
packet to a well-known public IP address (one of the root DNS servers) and |
|---|
| 489 |
seeing which network interface would be used. This will tend to find the |
|---|
| 490 |
outbound default route, which of course is only externally-visible if the |
|---|
| 491 |
host is externally-visible. Applications should not depend upon this giving a |
|---|
| 492 |
useful value, and should give the user a way to configure a list of |
|---|
| 493 |
hostname+portnumbers so that manually-configured firewalls, port forwarders, |
|---|
| 494 |
and NAT boxes can be dealt with. |
|---|
| 495 |
|
|---|
| 496 |
|
|---|
| 497 |
* Release 0.2.4 (28 Jan 2008) |
|---|
| 498 |
|
|---|
| 499 |
** Compatibility |
|---|
| 500 |
|
|---|
| 501 |
All releases between 0.1.3 and 0.2.4 (inclusive) are fully wire-compatible. |
|---|
| 502 |
|
|---|
| 503 |
** foolscap.logging Changes |
|---|
| 504 |
|
|---|
| 505 |
*** 'flogtool filter' command added |
|---|
| 506 |
|
|---|
| 507 |
This mode is used to take one event-log file and produce another with a |
|---|
| 508 |
subset of the events. There are several options to control the filtering: |
|---|
| 509 |
"--strip-facility=foolscap" would remove all the foolscap-related messages, |
|---|
| 510 |
and "--after=start --before=end" will retain events that occur within the |
|---|
| 511 |
given period. The syntax is still in flux, expect these options to change in |
|---|
| 512 |
the next few releases. The main idea is to take a very large logfile and turn |
|---|
| 513 |
it into a smaller, more manageable one. |
|---|
| 514 |
|
|---|
| 515 |
*** error logging |
|---|
| 516 |
|
|---|
| 517 |
Applications should avoid recording application-specific instances in log |
|---|
| 518 |
events. Doing so will forces the log viewer to access the original source |
|---|
| 519 |
code. The current release of foolscap uses pickle, so such instances will be |
|---|
| 520 |
loadable if the viewer can import the same code, but future versions will |
|---|
| 521 |
probably switch to using Banana, at which point trying to log such instances |
|---|
| 522 |
will cause an error. |
|---|
| 523 |
|
|---|
| 524 |
In this release, foolscap stringifies the type of an exception/Failure passed |
|---|
| 525 |
in through the failure= kwarg, to avoid inducing this import dependency in |
|---|
| 526 |
serialized Failures. It also uses the CopiedFailure code to improve |
|---|
| 527 |
portability of Failure instances, and CopiedFailures have been made |
|---|
| 528 |
pickleable. |
|---|
| 529 |
|
|---|
| 530 |
The preferred way to log a Failure instance is to pass it like so: |
|---|
| 531 |
|
|---|
| 532 |
def _oops(f): |
|---|
| 533 |
log.msg("Oh no, it failed", failure=f, level=log.BAD) |
|---|
| 534 |
d.addErrback(_oops) |
|---|
| 535 |
|
|---|
| 536 |
Finally, a 'log.err()' method was added, which behaves just like Twisted's |
|---|
| 537 |
normal log.err(): it can be used in a Deferred errback, or inside an |
|---|
| 538 |
exception handler. |
|---|
| 539 |
|
|---|
| 540 |
*** 'flogtool web-viewer' |
|---|
| 541 |
|
|---|
| 542 |
Adding a "sort=time" query argument to the all-events viewing page URL will |
|---|
| 543 |
turn off the default nested view, and instead will sort all events strictly |
|---|
| 544 |
by time of generation (note that unsynchronized clocks may confuse the |
|---|
| 545 |
relative ordering of events on different machines). "sort=number" sorts all |
|---|
| 546 |
events by their event number, which is of dubious utility (since these |
|---|
| 547 |
numbers are only scoped to the Tub). "sort=nested" is the default mode. |
|---|
| 548 |
|
|---|
| 549 |
The web-viewer now provides "summary views", which show just the events that |
|---|
| 550 |
occurred at a given severity level. Each event is a hyperlink to the line in |
|---|
| 551 |
the all-events page (using anchor/fragment tags), which may make them more |
|---|
| 552 |
convenient to bookmark or reference externally. |
|---|
| 553 |
|
|---|
| 554 |
|
|---|
| 555 |
* Release 0.2.3 (24 Dec 2007) |
|---|
| 556 |
|
|---|
| 557 |
** Compatibility |
|---|
| 558 |
|
|---|
| 559 |
All releases between 0.1.3 and 0.2.3 (inclusive) are fully wire-compatible. |
|---|
| 560 |
|
|---|
| 561 |
** Bug Fixes |
|---|
| 562 |
|
|---|
| 563 |
RemoteReference.getSturdyRef() didn't work (due to bitrot). It has been |
|---|
| 564 |
fixed. |
|---|
| 565 |
|
|---|
| 566 |
** foolscap.logging Changes |
|---|
| 567 |
|
|---|
| 568 |
This release is mostly about flogging improvements: some bugs and misfeatures |
|---|
| 569 |
were fixed: |
|---|
| 570 |
|
|---|
| 571 |
*** tolerate '%' in log message format strings |
|---|
| 572 |
|
|---|
| 573 |
Dictionary-style kwarg formatting is now done with a twisted-style style |
|---|
| 574 |
format= argument instead of happening implicitly. That means the acceptable |
|---|
| 575 |
ways to call foolscap.logging.log.msg are: |
|---|
| 576 |
|
|---|
| 577 |
log.msg("plain string") |
|---|
| 578 |
log.msg("no args means use 0% interpolation") |
|---|
| 579 |
log.msg("pre-interpolated: %d apples" % apples) |
|---|
| 580 |
log.msg("posargs: %d apples and %d oranges", apples, oranges) |
|---|
| 581 |
log.msg(format="kwargs: %(numapples)d apples", numapples=numapples) |
|---|
| 582 |
|
|---|
| 583 |
The benefit of the latter two forms are that the arguments are recorded |
|---|
| 584 |
separately in the event dictionary, so viewing tools can filter on the |
|---|
| 585 |
structured data, think of something like: |
|---|
| 586 |
|
|---|
| 587 |
[e for e in allEvents if e.get("numapples",0) > 4] |
|---|
| 588 |
|
|---|
| 589 |
*** log facility names are now dot-separated, to match stdlib logging |
|---|
| 590 |
*** log levels are derived from numerical stdlib logging levels |
|---|
| 591 |
*** $FLOGFILE to capture flog events during 'trial' runs |
|---|
| 592 |
|
|---|
| 593 |
One challenge of the flogging system is that, once an application was changed |
|---|
| 594 |
to write events to flogging instead of twisted's log, those events do not |
|---|
| 595 |
show up in the normal places where twisted writes its logfiles. For full |
|---|
| 596 |
applications this will be less of an issue, because application startup will |
|---|
| 597 |
tell flogging where events should go (flogging is intended to supplant |
|---|
| 598 |
twisted logging for these applications). But for events emitted during unit |
|---|
| 599 |
tests, such as those driven by Trial, these events would get lost. |
|---|
| 600 |
|
|---|
| 601 |
To address this problem, the 0.2.3 flogging code looks for the "FLOGFILE" |
|---|
| 602 |
environment variable at import time. This specifies a filename where flog |
|---|
| 603 |
events (a series of pickled event dictionaries) should be written. The file |
|---|
| 604 |
is opened at import time, events are written during the lifetime of the |
|---|
| 605 |
process, then the file is closed at shutdown using a Twisted "system event |
|---|
| 606 |
trigger" (which happens to be enough to work properly under Trial: other |
|---|
| 607 |
environments may not work so well). If the FLOGFILE filename ends in .bz2, |
|---|
| 608 |
the event pickles will be compressed, which is highly recommended because it |
|---|
| 609 |
can result in a 30x space savings (and e.g. the Tahoe unit test run results |
|---|
| 610 |
in 90MB of uncompressed events). All 'flogtool' modes know how to handle a |
|---|
| 611 |
.bz2 compressed flogfile as well as an uncompressed one. |
|---|
| 612 |
|
|---|
| 613 |
The "FLOGTWISTED" environment variable, if set, will cause this same code to |
|---|
| 614 |
bridge twisted log messages into the flogfile. This makes it easier to see |
|---|
| 615 |
the relative ordering of Twisted actions and foolscap/application events. |
|---|
| 616 |
(without this it becomes very hard to correlate the two sources of events). |
|---|
| 617 |
|
|---|
| 618 |
The "FLOGLEVEL" variable specifies a minimum severity level that will be put |
|---|
| 619 |
into the flogfile. This defaults to "1", which puts pretty much everything |
|---|
| 620 |
into the file. The idea is that, for tests, you might as well record |
|---|
| 621 |
everything, and use the filtering tools to control the display and isolate |
|---|
| 622 |
the important events. Real applications will use more sophisticated tradeoffs |
|---|
| 623 |
between disk space and interpretation effort. |
|---|
| 624 |
|
|---|
| 625 |
The recommended way to run Trial on a unit test suite for an application that |
|---|
| 626 |
uses Foolscap is: |
|---|
| 627 |
|
|---|
| 628 |
FLOGFILE=flog.out FLOGTWISTED=1 trial PACKAGENAME |
|---|
| 629 |
|
|---|
| 630 |
Note that the logfile cannot be placed in _trial_temp/, because trial deletes |
|---|
| 631 |
that directory after flogging creates the logfile, so the logfile would get |
|---|
| 632 |
deleted too. Also note that the file created by $FLOGFILE is truncated on |
|---|
| 633 |
each run of the program. |
|---|
| 634 |
|
|---|
| 635 |
|
|---|
| 636 |
* Release 0.2.2 (12 Dec 2007) |
|---|
| 637 |
|
|---|
| 638 |
** Compatibility |
|---|
| 639 |
|
|---|
| 640 |
All releases between 0.1.3 and 0.2.2 (inclusive) are fully wire-compatible. |
|---|
| 641 |
New (optional) negotiation parameters were added in 0.2.1 (really in 0.2.0). |
|---|
| 642 |
|
|---|
| 643 |
** Bug Fixes |
|---|
| 644 |
|
|---|
| 645 |
The new duplicate-connection handling code in 0.2.1 was broken. This release |
|---|
| 646 |
probably fixes it. |
|---|
| 647 |
|
|---|
| 648 |
There were other bugs in 0.2.1 which were triggered when a duplicate |
|---|
| 649 |
connection was shut down, causing remote calls to never be retired, which |
|---|
| 650 |
would also prevent the Reconnector from doing its job. These should be fixed |
|---|
| 651 |
now. |
|---|
| 652 |
|
|---|
| 653 |
** Other Changes |
|---|
| 654 |
|
|---|
| 655 |
Foolscap's connection-negotiation mechanism has been modified to use foolscap |
|---|
| 656 |
logging ("flog") instead of twisted.log . |
|---|
| 657 |
|
|---|
| 658 |
Setting the FLOGFILE= environment variable will cause a Foolscap-using |
|---|
| 659 |
program to write pickled log events to a file of that name. This is |
|---|
| 660 |
particularly useful when you want to record log events during 'trial' unit |
|---|
| 661 |
test run. The normal API for setting this file will be added later. The |
|---|
| 662 |
FLOGTWISTED= environment variable will cause the creation of a twisted.log |
|---|
| 663 |
bridge, to copy all events from the twisted log into the foolscap log. |
|---|
| 664 |
|
|---|
| 665 |
The 'flogtool web-view' mode has been enhanced to color-code events according |
|---|
| 666 |
to their severity, and to format Failure tracebacks in a more-readable way. |
|---|
| 667 |
|
|---|
| 668 |
|
|---|
| 669 |
* Release 0.2.1 (10 Dec 2007) |
|---|
| 670 |
|
|---|
| 671 |
** Compatibility |
|---|
| 672 |
|
|---|
| 673 |
All releases between 0.1.3 and 0.2.1 (inclusive) are fully wire-compatible. |
|---|
| 674 |
0.2.1 introduces some new negotiation parameters (to handle duplicate |
|---|
| 675 |
connections better), but these are ignored by older versions, and their lack |
|---|
| 676 |
is tolerated by 0.2.1 . |
|---|
| 677 |
|
|---|
| 678 |
** New Features |
|---|
| 679 |
|
|---|
| 680 |
*** new logging support |
|---|
| 681 |
|
|---|
| 682 |
Foolscap is slowly acquiring advanced diagnostic event-logging features. See |
|---|
| 683 |
doc/logging.xhtml for the philosophy and design of this logging system. 0.2.1 |
|---|
| 684 |
contains the first few pieces, including a tool named bin/flogtool that can |
|---|
| 685 |
be used to watch events on a running system, or gather events from multiple |
|---|
| 686 |
applications into a single place for later analysis. This support is still |
|---|
| 687 |
preliminary, and many of the controls and interfaces described in that |
|---|
| 688 |
document are not yet implemented. |
|---|
| 689 |
|
|---|
| 690 |
*** better handling of duplicate connections / NAT problems |
|---|
| 691 |
|
|---|
| 692 |
The connection-management code in 0.1.7 and earlier interacted badly with |
|---|
| 693 |
programs that run behind NAT boxes (especially those with aggressive |
|---|
| 694 |
connection timeouts) or on laptops which get unplugged from the network |
|---|
| 695 |
abruptly. Foolscap seeks to avoid duplicate connections, and various |
|---|
| 696 |
situtations could cause the two ends to disagree about the viability of any |
|---|
| 697 |
given connection. The net result (no pun intended) was that a client might |
|---|
| 698 |
have to wait up to 35 minutes (depending upon various timeout values) before |
|---|
| 699 |
being able to reestablish a connection, and the Reconnector's exponential |
|---|
| 700 |
backoff strategy could easily push this into 90 minutes of downtime. |
|---|
| 701 |
|
|---|
| 702 |
0.2.1 uses a different approach to accomplish duplicate-suppression, and |
|---|
| 703 |
should provide much faster reconnection after netquakes. To benefit from |
|---|
| 704 |
this, both ends must be running foolscap-0.2.1 or newer, however there is an |
|---|
| 705 |
additional setting (not enabled by default) to improve the behavior of |
|---|
| 706 |
pre-0.2.1 clients: tub.setOption("handle-old-duplicate-connections", True). |
|---|
| 707 |
|
|---|
| 708 |
*** new Reconnector methods |
|---|
| 709 |
|
|---|
| 710 |
The Reconnector object (as returned by Tub.connectTo) now has three utility |
|---|
| 711 |
methods that may be useful during debugging. reset() drops the backoff timer |
|---|
| 712 |
down to one second, causing the Reconnector to reconnect quickly: you could |
|---|
| 713 |
use this to avoid an hour-long delay if you've just restarted the server or |
|---|
| 714 |
re-enabled a network connection that was the cause of the earlier connection |
|---|
| 715 |
failures. getDelayUntilNextAttempt() returns the number of seconds remaining |
|---|
| 716 |
until the next connection attempt. And getLastFailure() returns a Failure |
|---|
| 717 |
object explaining why the last connection attempt failed, which may be a |
|---|
| 718 |
useful diagnostic in trying to resolve the connection problems. |
|---|
| 719 |
|
|---|
| 720 |
** Bug Fixes |
|---|
| 721 |
|
|---|
| 722 |
There were other minor changes: an OS-X unit test failure was resolved, |
|---|
| 723 |
CopiedFailures are serialized in a way that doesn't cause constraint |
|---|
| 724 |
violations, and the figleaf code-coverage tools (used by foolscap developers |
|---|
| 725 |
to measure how well the unit tests exercise the code base) have been improved |
|---|
| 726 |
(including an emacs code-used/unused annotation tool). |
|---|
| 727 |
|
|---|
| 728 |
|
|---|
| 729 |
* Release 0.2.0 (10 Dec 2007) |
|---|
| 730 |
|
|---|
| 731 |
This release had a fatal bug that wasn't caught by the unit tests, and was |
|---|
| 732 |
superseded almost immediately by 0.2.1 . |
|---|
| 733 |
|
|---|
| 734 |
|
|---|
| 735 |
* Release 0.1.7 (24 Sep 2007) |
|---|
| 736 |
|
|---|
| 737 |
** Compatibility |
|---|
| 738 |
|
|---|
| 739 |
All releases between 0.1.3 and 0.1.7 (inclusive) are fully wire-compatible. |
|---|
| 740 |
|
|---|
| 741 |
** Bug Fixes |
|---|
| 742 |
|
|---|
| 743 |
*** slow remote_ methods shouldn't delay subsequent messages (#25) |
|---|
| 744 |
|
|---|
| 745 |
In earlier releases, a remote_ method which runs slowly (i.e. one which |
|---|
| 746 |
returns a Deferred and does not fire it right away) would have the |
|---|
| 747 |
unfortunate side-effect of delaying all subsequent calls from the same |
|---|
| 748 |
Broker. Those later calls would not be delivered until the first message had |
|---|
| 749 |
completed processing. If, for some reason, that Deferred were never fired, |
|---|
| 750 |
this Foolscap bug would prevent any other remote_ methods from ever being |
|---|
| 751 |
called. |
|---|
| 752 |
|
|---|
| 753 |
This is not how Foolscap's message-ordering logic is designed to work. |
|---|
| 754 |
Foolscap guarantees in-order *delivery* of messages, but does not require |
|---|
| 755 |
that they be completed/retired in that same order. |
|---|
| 756 |
|
|---|
| 757 |
This has now been fixed. The invocation of remote_* is done in-order: any |
|---|
| 758 |
further sequencing is up to the receiving application. |
|---|
| 759 |
|
|---|
| 760 |
For example, in the following code: |
|---|
| 761 |
|
|---|
| 762 |
sender: |
|---|
| 763 |
rref.callRemote("quick", 1) |
|---|
| 764 |
rref.callRemote("slow", 2) |
|---|
| 765 |
rref.callRemote("quick", 3) |
|---|
| 766 |
|
|---|
| 767 |
receiver: |
|---|
| 768 |
def remote_quick(self, num): |
|---|
| 769 |
print num |
|---|
| 770 |
def remote_slow(self, num): |
|---|
| 771 |
print num |
|---|
| 772 |
d = Deferred() |
|---|
| 773 |
def _done(): |
|---|
| 774 |
print "DONE" |
|---|
| 775 |
d.callback(None) |
|---|
| 776 |
reactor.callLater(5.0, _done) |
|---|
| 777 |
return d |
|---|
| 778 |
|
|---|
| 779 |
The intended order of printed messages is 1,2,3,DONE . This bug caused the |
|---|
| 780 |
ordering to be 1,2,DONE,3 instead. |
|---|
| 781 |
|
|---|
| 782 |
*** default size limits removed from all Constraints (#26) |
|---|
| 783 |
|
|---|
| 784 |
Constraints in Foolscap serve two purposes: DoS attack mitigation, and strong |
|---|
| 785 |
typing on remote interfaces to help developers find problems sooner. To |
|---|
| 786 |
support the former, most container-based Constraints had default size limits. |
|---|
| 787 |
For example, the default StringConstraint enforced a maximum length of 1000 |
|---|
| 788 |
characters, and the ListConstraint had a maxLength of 30 elements. |
|---|
| 789 |
|
|---|
| 790 |
In practice, these limits turned out to be more surprising than helpful. |
|---|
| 791 |
Applications which worked fine in testing would mysteriously break when |
|---|
| 792 |
subjected to data that was larger than expected. Developers who used |
|---|
| 793 |
Constraints for their type-checking properties were surprised to discover |
|---|
| 794 |
that they were getting size limitations as well. In addition, the |
|---|
| 795 |
DoS-mitigation code in foolscap is not yet complete, so the cost/benefit |
|---|
| 796 |
ratio of this feature was dubious. |
|---|
| 797 |
|
|---|
| 798 |
For these reasons, all default size limits have been removed from this |
|---|
| 799 |
release. The 0.1.7 StringConstraint() schema is equivalent to the 0.1.6 |
|---|
| 800 |
StringConstraint(maxLength=None) version. To get the 0.1.6 behavior, use |
|---|
| 801 |
StringConstraint(maxLength=1000). The same is true for ListConstraint, |
|---|
| 802 |
DictConstraint, SetConstraint, and UnicodeConstraint. |
|---|
| 803 |
|
|---|
| 804 |
** New features |
|---|
| 805 |
|
|---|
| 806 |
*** Tub.registerReference(furlFile=) |
|---|
| 807 |
|
|---|
| 808 |
In the spirit of Tub(certFile=), a new argument was added to |
|---|
| 809 |
registerReference that instructs Foolscap to find and store a |
|---|
| 810 |
randomly-generated name in the given file. This makes it convenient to allow |
|---|
| 811 |
subsequent invocations of the same program to use the same stable (yet |
|---|
| 812 |
unguessable) identifier for long-lived objects. For example, a Foolscap-based |
|---|
| 813 |
server can make its Server object available under the same FURL from one run |
|---|
| 814 |
of the program to the next with the following startup code: |
|---|
| 815 |
|
|---|
| 816 |
s = MyServer() |
|---|
| 817 |
furl = tub.registerReference(s, furlFile=os.path.join(basedir, "server")) |
|---|
| 818 |
|
|---|
| 819 |
If the furlFile= exists before registerReference is called, a FURL will be |
|---|
| 820 |
read from it, and a name extracted to use for the object. If not, the file |
|---|
| 821 |
will be created and filled with a FURL that uses a randomly-generated name. |
|---|
| 822 |
|
|---|
| 823 |
*** Tub.serialize() |
|---|
| 824 |
|
|---|
| 825 |
Work is ongoing to implement E-style cryptographic Sealers/Unsealers in |
|---|
| 826 |
Foolscap (see ticket #20). Part of that work has made it into this release. |
|---|
| 827 |
The new Tub.serialize() and Tub.unserialize() methods provide access to the |
|---|
| 828 |
underlying object-graph-serialization code. Normally this code is used to |
|---|
| 829 |
construct a bytestream that is immediately sent over an SSL connection to a |
|---|
| 830 |
remote host; these methods return a string instead. Eventually, a Sealer will |
|---|
| 831 |
return an encrypted version of this string, and the corresponding Unsealer |
|---|
| 832 |
will take the encrypted string and build a new object graph. |
|---|
| 833 |
|
|---|
| 834 |
The foolscap.serialize() and .unserialize() functions have existed for a |
|---|
| 835 |
while. The new Tub.serialize()/.unserialize() methods are special in that you |
|---|
| 836 |
can serialize Referenceables and RemoteReferences. These are encoded with |
|---|
| 837 |
their FURLs, so that the unserializing Tub can establish a new live reference |
|---|
| 838 |
to their targets. foolscap.serialize() cannot handle referenceables. |
|---|
| 839 |
|
|---|
| 840 |
Note that both Tub.serialize() and foolscap.serialize() are currently |
|---|
| 841 |
"unsafe", in that they will serialize (and unserialize!) instances of |
|---|
| 842 |
arbitrary classes, much like the stdlib pickle module. This is a significant |
|---|
| 843 |
security problem, as this results in arbitrary object constructors being |
|---|
| 844 |
executed during deserialization. In a future release of Foolscap, this mode |
|---|
| 845 |
of operation will *not* be the default, and a special argument will have to |
|---|
| 846 |
be passed to enable such behavior. |
|---|
| 847 |
|
|---|
| 848 |
|
|---|
| 849 |
** Other Improvements |
|---|
| 850 |
|
|---|
| 851 |
When methods fail, the error messages that get logged have been improved. The |
|---|
| 852 |
new messages contain information about which source+dest TubIDs were |
|---|
| 853 |
involved, and which RemoteInterface and method name was being used. |
|---|
| 854 |
|
|---|
| 855 |
A new internal method named Tub.debug_listBrokers() will provide information |
|---|
| 856 |
on which messages are waiting for delivery, either inbound or outbound. It is |
|---|
| 857 |
intended to help diagnose problems like #25. Any message which remains |
|---|
| 858 |
unresolved for a significant amount of time is likely to indicate a problem. |
|---|
| 859 |
|
|---|
| 860 |
|
|---|
| 861 |
* Release 0.1.6 (02 Sep 2007) |
|---|
| 862 |
|
|---|
| 863 |
** Compatibility |
|---|
| 864 |
|
|---|
| 865 |
All releases between 0.1.3 and 0.1.6 (inclusive) are fully wire-compatible. |
|---|
| 866 |
|
|---|
| 867 |
** Bug Fixes |
|---|
| 868 |
|
|---|
| 869 |
Using a schema of ChoiceOf(StringConstraint(2000), None) would fail to accept |
|---|
| 870 |
strings between 1000 and 2000 bytes: it would accept a short string, or None, |
|---|
| 871 |
but not a long string. This has been fixed. ChoiceOf() remains a troublesome |
|---|
| 872 |
constraint: having it is awfully nice, and things like ChoiceOf(str,None) |
|---|
| 873 |
seem to work, but it is unreliable. Using ChoiceOf with non-terminal children |
|---|
| 874 |
is not recommended (the garden-path problem is unlikely to be easy to solve): |
|---|
| 875 |
schemas are not regular expressions. |
|---|
| 876 |
|
|---|
| 877 |
The debian packaging rules have been fixed. The ones in 0.1.5 failed to run |
|---|
| 878 |
because of some renamed documentation files. |
|---|
| 879 |
|
|---|
| 880 |
** Minor Fixes |
|---|
| 881 |
|
|---|
| 882 |
Several minor documentation errors have been corrected. A new 'make api-docs' |
|---|
| 883 |
target has been added to run epydoc and build HTML versions of the API |
|---|
| 884 |
documentation. |
|---|
| 885 |
|
|---|
| 886 |
When a remote method fails and needs to send a traceback over the wire, and |
|---|
| 887 |
when the traceback is too large, trim out the middle rather than the end, |
|---|
| 888 |
since usually it's the beginning and the end that are the most useful. |
|---|
| 889 |
|
|---|
| 890 |
|
|---|
| 891 |
* Release 0.1.5 (07 Aug 2007) |
|---|
| 892 |
|
|---|
| 893 |
** Compatibility |
|---|
| 894 |
|
|---|
| 895 |
This release is fully compatible with 0.1.4 and 0.1.3 . |
|---|
| 896 |
|
|---|
| 897 |
** CopiedFailure improvements |
|---|
| 898 |
|
|---|
| 899 |
When a remote method call fails, the calling side gets back a CopiedFailure |
|---|
| 900 |
instance. These instances now behave slightly more like the (local) Failure |
|---|
| 901 |
objects that they are intended to mirror, in that .type now behaves much like |
|---|
| 902 |
the original class. This should allow trial tests which result in a |
|---|
| 903 |
CopiedFailure to be logged without exploding. In addition, chained failures |
|---|
| 904 |
(where A calls B, and B calls C, and C fails, so C's Failure is eventually |
|---|
| 905 |
returned back to A) should work correctly now. |
|---|
| 906 |
|
|---|
| 907 |
** Gift improvements |
|---|
| 908 |
|
|---|
| 909 |
Gifts inside return values should properly stall the delivery of the response |
|---|
| 910 |
until the gift is resolved. Gifts in all sorts of containers should work |
|---|
| 911 |
properly now. Gifts which cannot be resolved successfully (either because the |
|---|
| 912 |
hosting Tub cannot be reached, or because the name cannot be found) will now |
|---|
| 913 |
cause a proper error rather than hanging forever. Unresolvable gifts in |
|---|
| 914 |
method arguments will cause the message to not be delivered and an error to |
|---|
| 915 |
be returned to the caller. Unresolvable gifts in method return values will |
|---|
| 916 |
cause the caller to receive an error. |
|---|
| 917 |
|
|---|
| 918 |
** IRemoteReference() adapter |
|---|
| 919 |
|
|---|
| 920 |
The IRemoteReference() interface now has an adapter from Referenceable which |
|---|
| 921 |
creates a wrapper that enables the use of callRemote() and other |
|---|
| 922 |
IRemoteReference methods on a local object. |
|---|
| 923 |
|
|---|
| 924 |
The situation where this might be useful is when you have a central |
|---|
| 925 |
introducer and a bunch of clients, and the clients are introducing themselves |
|---|
| 926 |
to each other (to create a fully-connected mesh), and the introductions are |
|---|
| 927 |
using live references (i.e. Gifts), then when a specific client learns about |
|---|
| 928 |
itself from the introducer, that client will receive a local object instead |
|---|
| 929 |
of a RemoteReference. Each client will wind up with n-1 RemoteReferences and |
|---|
| 930 |
a single local object. |
|---|
| 931 |
|
|---|
| 932 |
This adapter allows the client to treat all these introductions as equal. A |
|---|
| 933 |
client that wishes to send a message to everyone it's been introduced to |
|---|
| 934 |
(including itself) can use: |
|---|
| 935 |
|
|---|
| 936 |
for i in introductions: |
|---|
| 937 |
IRemoteReference(i).callRemote("hello", args) |
|---|
| 938 |
|
|---|
| 939 |
In the future, if we implement coercing Guards (instead of |
|---|
| 940 |
compliance-asserting Constraints), then IRemoteReference will be useful as a |
|---|
| 941 |
guard on methods that want to insure that they can do callRemote (and |
|---|
| 942 |
notifyOnDisconnect, etc) on their argument. |
|---|
| 943 |
|
|---|
| 944 |
** Tub.registerNameLookupHandler |
|---|
| 945 |
|
|---|
| 946 |
This method allows a one-argument name-lookup callable to be attached to the |
|---|
| 947 |
Tub. This augments the table maintained by Tub.registerReference, allowing |
|---|
| 948 |
Referenceables to be created on the fly, or persisted/retrieved on disk |
|---|
| 949 |
instead of requiring all of them to be generated and registered at startup. |
|---|
| 950 |
|
|---|
| 951 |
|
|---|
| 952 |
* Release 0.1.4 (14 May 2007) |
|---|
| 953 |
|
|---|
| 954 |
** Compatibility |
|---|
| 955 |
|
|---|
| 956 |
This release is fully compatible with 0.1.3 . |
|---|
| 957 |
|
|---|
| 958 |
** getReference/connectTo can be called before Tub.startService() |
|---|
| 959 |
|
|---|
| 960 |
The Tub.startService changes that were suggested in the 0.1.3 release notes |
|---|
| 961 |
have been implemented. Calling getReference() or connectTo() before the Tub |
|---|
| 962 |
has been started is now allowed, however no action will take place until the |
|---|
| 963 |
Tub is running. Don't forget to start the Tub, or you'll be left wondering |
|---|
| 964 |
why your Deferred or callback is never fired. (A log message is emitted when |
|---|
| 965 |
these calls are made before the Tub is started, in the hopes of helping |
|---|
| 966 |
developers find this mistake faster). |
|---|
| 967 |
|
|---|
| 968 |
** constraint improvements |
|---|
| 969 |
|
|---|
| 970 |
The RIFoo -style constraint now accepts gifts (third-party references). This |
|---|
| 971 |
also means that using RIFoo on the outbound side will accept either a |
|---|
| 972 |
Referenceable that implements the given RemoteInterface or a RemoteReference |
|---|
| 973 |
that points to a Referenceable that implements the given RemoteInterface. |
|---|
| 974 |
There is a situation (sending a RemoteReference back to its owner) that will |
|---|
| 975 |
pass the outbound constraint but be rejected by the inbound constraint on the |
|---|
| 976 |
other end. It remains to be seen how this will be fixed. |
|---|
| 977 |
|
|---|
| 978 |
** foolscap now deserializes into python2.4-native 'set' and 'frozenset' types |
|---|
| 979 |
|
|---|
| 980 |
Since Foolscap is dependent upon python2.4 or newer anyways, it now |
|---|
| 981 |
unconditionally creates built-in 'set' and 'frozenset' instances when |
|---|
| 982 |
deserializing 'set'/'immutable-set' banana sequences. The pre-python2.4 |
|---|
| 983 |
'sets' module has non-built-in set classes named sets.Set and |
|---|
| 984 |
sets.ImmutableSet, and these are serialized just like the built-in forms. |
|---|
| 985 |
|
|---|
| 986 |
Unfortunately this means that Set and ImmutableSet will not survive a |
|---|
| 987 |
round-trip: they'll be turned into set and frozenset, respectively. Worse |
|---|
| 988 |
yet, 'set' and 'sets.Set' are not entirely compatible. This may cause a |
|---|
| 989 |
problem for older applications that were written to be compatible with both |
|---|
| 990 |
python-2.3 and python-2.4 (by using sets.Set/sets.ImmutableSet), for which |
|---|
| 991 |
the compatibility code is still in place (i.e. they are not using |
|---|
| 992 |
set/frozenset). These applications may experience problems when set objects |
|---|
| 993 |
that traverse the wire via Foolscap are brought into close proximity with set |
|---|
| 994 |
objects that remained local. This is unfortunate, but it's the cleanest way |
|---|
| 995 |
to support modern applications that use the native types exclusively. |
|---|
| 996 |
|
|---|
| 997 |
** bug fixes |
|---|
| 998 |
|
|---|
| 999 |
Gifts inside containers (lists, tuples, dicts, sets) were broken: the target |
|---|
| 1000 |
method was frequently invoked before the gift had properly resolved into a |
|---|
| 1001 |
RemoteReference. Constraints involving gifts inside containers were broken |
|---|
| 1002 |
too. The constraints may be too loose right now, but I don't think they |
|---|
| 1003 |
should cause false negatives. |
|---|
| 1004 |
|
|---|
| 1005 |
The unused SturdyRef.asLiveRef method was removed, since it didn't work |
|---|
| 1006 |
anyways. |
|---|
| 1007 |
|
|---|
| 1008 |
** terminology shift: FURL |
|---|
| 1009 |
|
|---|
| 1010 |
The preferred name for the sort of URL that you get back from |
|---|
| 1011 |
registerReference (and hand to getReference or connectTo) has changed from |
|---|
| 1012 |
"PB URL" to "FURL" (short for Foolscap URL). They still start with 'pb:', |
|---|
| 1013 |
however. Documentation is slowly being changed to use this term. |
|---|
| 1014 |
|
|---|
| 1015 |
|
|---|
| 1016 |
* Release 0.1.3 (02 May 2007) |
|---|
| 1017 |
|
|---|
| 1018 |
** Incompatibility Warning |
|---|
| 1019 |
|
|---|
| 1020 |
The 'keepalive' feature described below adds a new pair of banana tokens, |
|---|
| 1021 |
PING and PONG, which introduces a compatibility break between 0.1.2 and 0.1.3 |
|---|
| 1022 |
. Older versions would throw an error upon receipt of a PING token, so the |
|---|
| 1023 |
version-negotiation mechanism is used to prevent banana-v2 (0.1.2) peers from |
|---|
| 1024 |
connecting to banana-v3 (0.1.3+) peers. Our negotiation mechanism would make |
|---|
| 1025 |
it possible to detect the older (v2) peer and refrain from using PINGs, but |
|---|
| 1026 |
that has not been done for this release. |
|---|
| 1027 |
|
|---|
| 1028 |
** Tubs must be running before use |
|---|
| 1029 |
|
|---|
| 1030 |
Tubs are twisted.application.service.Service instances, and as such have a |
|---|
| 1031 |
clear distinction between "running" and "not running" states. Tubs are |
|---|
| 1032 |
started by calling startService(), or by attaching them to a running service, |
|---|
| 1033 |
or by starting the service that they are already attached to. The design rule |
|---|
| 1034 |
in operation here is that Tubs are not allowed to perform network IO until |
|---|
| 1035 |
they are running. |
|---|
| 1036 |
|
|---|
| 1037 |
This rule was not enforced completely in 0.1.2, and calls to |
|---|
| 1038 |
getReference()/connectTo() that occurred before the Tub was started would |
|---|
| 1039 |
proceed normally (initiating a TCP connection, etc). Starting with 0.1.3, |
|---|
| 1040 |
this rule *is* enforced. For now, that means that you must start the Tub |
|---|
| 1041 |
before calling either of these methods, or you'll get an exception. In a |
|---|
| 1042 |
future release, that may be changed to allow these early calls, and queue or |
|---|
| 1043 |
otherwise defer the network IO until the Tub is eventually started. (the |
|---|
| 1044 |
biggest issue is how to warn users who forget to start the Tub, since in the |
|---|
| 1045 |
face of such a bug the getReference will simply never complete). |
|---|
| 1046 |
|
|---|
| 1047 |
** Keepalives |
|---|
| 1048 |
|
|---|
| 1049 |
Tubs now keep track of how long a connection has been idle, and will send a |
|---|
| 1050 |
few bytes (a PING of the other end) if no other traffic has been seen for |
|---|
| 1051 |
roughly 4 to 8 minutes. This serves two purposes. The first is to convince an |
|---|
| 1052 |
intervening NAT box that the connection is still in use, to prevent it from |
|---|
| 1053 |
discarding the connection's table entry, since that would block any further |
|---|
| 1054 |
traffic. The second is to accelerate the detection of such blocked |
|---|
| 1055 |
connections, specifically to reduce the size of a window of buggy behavior in |
|---|
| 1056 |
Foolscap's duplicate-connection detection/suppression code. |
|---|
| 1057 |
|
|---|
| 1058 |
This problem arises when client A (behind a low-end NAT box) connects to |
|---|
| 1059 |
server B, perhaps using connectTo(). The first connection works fine, and is |
|---|
| 1060 |
used for a while. Then, for whatever reason, A and B are silent for a long |
|---|
| 1061 |
time (perhaps as short as 20 minutes, depending upon the NAT box). During |
|---|
| 1062 |
this silence, A's NAT box thinks the connection is no longer in use and drops |
|---|
| 1063 |
the address-translation table entry. Now suppose that A suddenly decides to |
|---|
| 1064 |
talk to B. If the NAT box creates a new entry (with a new outbound port |
|---|
| 1065 |
number), the packets that arrive on B will be rejected, since they do not |
|---|
| 1066 |
match any existing TCP connections. A sees these rejected packets, breaks the |
|---|
| 1067 |
TCP connection, and the Reconnector initiates a new connection. Meanwhile, B |
|---|
| 1068 |
has no idea that anything has gone wrong. When the second connection reaches |
|---|
| 1069 |
B, it thinks this is a duplicate connection from A, and that it already has a |
|---|
| 1070 |
perfectly functional (albeit quiet) connection for that TubID, so it rejects |
|---|
| 1071 |
the connection during the negotiation phase. A sees this rejection and |
|---|
| 1072 |
schedules a new attempt, which ends in the same result. This has the |
|---|
| 1073 |
potential to prevent hosts behind NAT boxes from ever reconnecting to the |
|---|
| 1074 |
other end, at least until the the program at the far end is restarted, or it |
|---|
| 1075 |
happens to try to send some traffic of its own. |
|---|
| 1076 |
|
|---|
| 1077 |
The same problem can occur if a laptop is abruptly shut down, or unplugged |
|---|
| 1078 |
from the network, then moved to a different network. Similar problems have |
|---|
| 1079 |
been seen with virtual machine instances that were suspended and moved to a |
|---|
| 1080 |
different network. |
|---|
| 1081 |
|
|---|
| 1082 |
The longer-term fix for this is a deep change to the way duplicate |
|---|
| 1083 |
connections (and cross-connect race conditions) are handled. The keepalives, |
|---|
| 1084 |
however, mean that both sides are continually checking to see that the |
|---|
| 1085 |
connection is still usable, enabling TCP to break the connection once the |
|---|
| 1086 |
keepalives go unacknowledged for a certain amount of time. The default |
|---|
| 1087 |
keepalive timer is 4 minutes, and due to the way it is implemented this means |
|---|
| 1088 |
that no more than 8 minutes will pass without some traffic being sent. TCP |
|---|
| 1089 |
tends to time out connections after perhaps 15 minutes of unacknowledged |
|---|
| 1090 |
traffic, which means that the window of unconnectability is probably reduced |
|---|
| 1091 |
from infinity down to about 25 minutes. |
|---|
| 1092 |
|
|---|
| 1093 |
The keepalive-sending timer defaults to 4 minutes, and can be changed by |
|---|
| 1094 |
calling tub.setOption("keepaliveTimeout", seconds). |
|---|
| 1095 |
|
|---|
| 1096 |
In addition, an explicit disconnect timer can be enabled, which tells |
|---|
| 1097 |
Foolscap to drop the connection unless traffic has been seen within some |
|---|
| 1098 |
minimum span of time. This timer can be set by calling |
|---|
| 1099 |
tub.setOption("disconnectTimeout", seconds). Obviously it should be set to a |
|---|
| 1100 |
higher value than the keepaliveTimeout. This will close connections faster |
|---|
| 1101 |
than TCP will. Both TCP disconnects and the ones triggered by this |
|---|
| 1102 |
disconnectTimeout run the risk of false negatives, of course, in the face of |
|---|
| 1103 |
unreliable networks. |
|---|
| 1104 |
|
|---|
| 1105 |
** New constraints |
|---|
| 1106 |
|
|---|
| 1107 |
When a tuple appears in a method constraint specification, it now maps to an |
|---|
| 1108 |
actual TupleOf constraint. Previously they mapped to a ChoiceOf constraint. |
|---|
| 1109 |
In practice, TupleOf appears to be much more useful, and thus better |
|---|
| 1110 |
deserving of the shortcut. |
|---|
| 1111 |
|
|---|
| 1112 |
For example, a method defined as follows: |
|---|
| 1113 |
|
|---|
| 1114 |
def get_employee(idnumber=int): |
|---|
| 1115 |
return (str, int, int) # (name, room_number, age) |
|---|
| 1116 |
|
|---|
| 1117 |
can only return a three-element tuple, in which the first element is a string |
|---|
| 1118 |
(specifically it conforms to a default StringConstraint), and the second two |
|---|
| 1119 |
elements are ints (which conform to a default IntegerConstraint, which means |
|---|
| 1120 |
it fits in a 32-bit signed twos-complement value). |
|---|
| 1121 |
|
|---|
| 1122 |
To specify a constraint that can accept alternatives, use ChoiceOf: |
|---|
| 1123 |
|
|---|
| 1124 |
def get_record(key=str): |
|---|
| 1125 |
"""Return the record (a string) if it is present, or None if |
|---|
| 1126 |
it is not present.""" |
|---|
| 1127 |
return ChoiceOf(str, None) |
|---|
| 1128 |
|
|---|
| 1129 |
UnicodeConstraint has been added, with minLength=, maxLength=, and regexp= |
|---|
| 1130 |
arguments. |
|---|
| 1131 |
|
|---|
| 1132 |
The previous StringConstraint has been renamed to ByteStringConstraint (for |
|---|
| 1133 |
accuracy), and it is defined to *only* accept string objects (not unicode |
|---|
| 1134 |
objects). 'StringConstraint' itself remains equivalent to |
|---|
| 1135 |
ByteStringConstraint for now, but in the future it may be redefined to be a |
|---|
| 1136 |
constraint that accepts both bytestrings and unicode objects. To accomplish |
|---|
| 1137 |
the bytestring-or-unicode constraint now, you might try |
|---|
| 1138 |
schema.AnyStringConstraint, but it has not been fully tested, and might not |
|---|
| 1139 |
work at all. |
|---|
| 1140 |
|
|---|
| 1141 |
** Bugfixes |
|---|
| 1142 |
|
|---|
| 1143 |
Errors during negotiation were sometimes delivered in the wrong format, |
|---|
| 1144 |
resulting in a "token prefix is limited to 64 bytes" error message. Several |
|---|
| 1145 |
error messages (including that one) have been improved to give developers a |
|---|
| 1146 |
better chance of determining where the actual problem lies. |
|---|
| 1147 |
|
|---|
| 1148 |
RemoteReference.notifyOnDisconnect was buggy when called on a reference that |
|---|
| 1149 |
was already broken: it failed to fire the callback. Now it fires the callback |
|---|
| 1150 |
soon (using an eventual-send). This should remove a race condition from |
|---|
| 1151 |
connectTo+notifyOnDisconnect sequences and allow them to operate reliably. |
|---|
| 1152 |
notifyOnDisconnect() is now tolerant of attempts to remove something twice, |
|---|
| 1153 |
which should make it easier to use safely. |
|---|
| 1154 |
|
|---|
| 1155 |
Remote methods which raise string exceptions should no longer cause Foolscap |
|---|
| 1156 |
to explode. These sorts of exceptions are deprecated, of course, and you |
|---|
| 1157 |
shouldn't use them, but at least they won't break Foolscap. |
|---|
| 1158 |
|
|---|
| 1159 |
The Reconnector class (accessed by tub.connectTo) was not correctly |
|---|
| 1160 |
reconnecting in certain cases (which appeared to be particularly common on |
|---|
| 1161 |
windows). This should be fixed now. |
|---|
| 1162 |
|
|---|
| 1163 |
CopyableSlicer did not work inside containers when streaming was enabled. |
|---|
| 1164 |
Thanks to iacovou-AT-gmail.com for spotting this one. |
|---|
| 1165 |
|
|---|
| 1166 |
** Bugs not fixed |
|---|
|
|---|