protected void _upload( BlobInfo bi, String tag ) throws ServerError, IOException {
		if( bi instanceof FileInfo ) {
			transferTracker.sendingFile( ((FileInfo)bi).getPath() );
		}
		
		InputStream is = bi.openInputStream();
		try {
			URL url = urlFor(bi.getUrn());
			
			if( inducePutErrors ) {
				throw new ServerError("Not a real server error; yuk yuk.", 599, null, "PUT", url.toString());
			}
			
			HttpURLConnection urlCon = (HttpURLConnection)url.openConnection();
			urlCon.setRequestMethod("PUT");
			urlCon.setDoOutput(true);
			OutputStream os = urlCon.getOutputStream();
			int totalSize = 0;
			try {
				byte[] buf = new byte[1024*1024];
				int r;
				while( (r = is.read(buf)) > 0 ) {
					totalSize += r;
					os.write(buf, 0, r);
				}
			} finally {
				os.close();
			}
			int status = urlCon.getResponseCode();
			if( debug ) System.err.println("PUT "+url+" ("+totalSize+" bytes) -> "+status);
			if( status < 200 || status >= 300 ) {
				byte[] errorText = null;
				try {
					errorText = StreamUtil.slurp(urlCon.getErrorStream());
				} catch( Exception e ) { }
				
				throw new ServerError(
					"PUT received unexpected response code "+status+"; "+urlCon.getResponseMessage(),
					status, errorText,
					"PUT", url.toString()
				);
			}
		} finally {
			is.close();
		}
		transferTracker.transferred(bi.getSize(), 1, tag);
	}